diff --git a/.eslintrc b/.eslintrc index ed8a063e..04919df6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,7 +5,6 @@ "semi": [ 2, "always" ], "keyword-spacing": [ 2, { "before": true, "after": true } ], "space-before-blocks": [ 2, "always" ], - "space-before-function-paren": [ 2, "always" ], "no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ], "no-cond-assign": [ 0 ] }, diff --git a/bin/buble b/bin/buble index 35643d9c..95af636d 100755 --- a/bin/buble +++ b/bin/buble @@ -1,7 +1,7 @@ #!/usr/bin/env node -var minimist = require( 'minimist' ); +var minimist = require('minimist'); -var command = minimist( process.argv.slice( 2 ), { +var command = minimist(process.argv.slice(2), { alias: { // Short options h: 'help', @@ -15,14 +15,10 @@ var command = minimist( process.argv.slice( 2 ), { } }); -if ( command.help || ( process.argv.length <= 2 && process.stdin.isTTY ) ) { - require( './showHelp' )(); -} - -else if ( command.version ) { - console.log( 'Bublé version ' + require( '../package.json' ).version ); -} - -else { - require( './runBuble' )( command ); +if (command.help || (process.argv.length <= 2 && process.stdin.isTTY)) { + require('./showHelp')(); +} else if (command.version) { + console.log('Bublé version ' + require('../package.json').version); // eslint-disable-line no-console +} else { + require('./runBuble')(command); } diff --git a/bin/handleError.js b/bin/handleError.js index ab9b69fb..4888adb9 100644 --- a/bin/handleError.js +++ b/bin/handleError.js @@ -1,46 +1,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); }; diff --git a/bin/runBuble.js b/bin/runBuble.js index 0e574742..cb621e34 100644 --- a/bin/runBuble.js +++ b/bin/runBuble.js @@ -1,48 +1,49 @@ -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, transforms: options.transforms, source: from, @@ -52,35 +53,35 @@ function compileFile ( from, to, command, options ) { namedFunctionExpressions: options.namedFunctionExpressions }); - 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' }); } @@ -91,58 +92,58 @@ module.exports = function ( command ) { target: {}, transforms: {}, 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); } }); } diff --git a/bin/showHelp.js b/bin/showHelp.js index 1cc19b65..770c5669 100644 --- a/bin/showHelp.js +++ b/bin/showHelp.js @@ -1,13 +1,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 }); }; diff --git a/src/index.js b/src/index.js index 093f8616..dbcaba39 100644 --- a/src/index.js +++ b/src/index.js @@ -5,58 +5,65 @@ import Program from './program/Program.js'; import { features, matrix } from './support.js'; import getSnippet from './utils/getSnippet.js'; -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 + ? 0b1111111111111111111111111111111 + : 0b1000000000000000000000000000000; - 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://gitlab.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://gitlab.com/Rich-Harris/buble/issues` + ); + const support = versions[targetVersion]; 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; }); return transforms; } -export function transform ( source, options = {} ) { +export function transform(source, options = {}) { let ast; let jsx = null; try { - ast = parse( source, { + ast = parse(source, { ecmaVersion: 8, preserveParens: true, sourceType: 'module', 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]; } }, plugins: { @@ -65,25 +72,27 @@ export function transform ( source, options = {} ) { } }); 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}`; 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'; diff --git a/src/program/BlockStatement.js b/src/program/BlockStatement.js index c749951f..f2a4351f 100644 --- a/src/program/BlockStatement.js +++ b/src/program/BlockStatement.js @@ -3,30 +3,30 @@ import Node from './Node.js'; import Scope from './Scope.js'; import destructure from '../utils/destructure.js'; -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'; } 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'); }); } } - initialise ( transforms ) { + initialise(transforms) { this.thisAlias = null; this.argumentsAlias = null; this.defaultParameters = []; @@ -35,65 +35,67 @@ export default class BlockStatement extends Node { // but in some cases (e.g. `for` statements), we need to create // the scope early, as it pertains to both the init block and // the body of the statement - if ( !this.scope ) this.createScope(); + if (!this.scope) this.createScope(); - this.body.forEach( node => node.initialise( transforms ) ); + this.body.forEach(node => node.initialise(transforms)); 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; 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'); } return this.argumentsAlias; } - getArgumentsArrayAlias () { - if ( !this.argumentsArrayAlias ) { - this.argumentsArrayAlias = this.scope.createIdentifier( 'argsArray' ); + getArgumentsArrayAlias() { + if (!this.argumentsArrayAlias) { + this.argumentsArrayAlias = this.scope.createIdentifier('argsArray'); } return this.argumentsArrayAlias; } - getThisAlias () { - if ( !this.thisAlias ) { - this.thisAlias = this.scope.createIdentifier( 'this' ); + getThisAlias() { + if (!this.thisAlias) { + this.thisAlias = this.scope.createIdentifier('this'); } return this.thisAlias; } - getIndentation () { - if ( this.indentation === undefined ) { + getIndentation() { + if (this.indentation === undefined) { const source = this.program.magicString.original; const useOuter = this.synthetic || !this.body.length; let c = useOuter ? this.start : this.body[0].start; - while ( c && source[c] !== '\n' ) c -= 1; + while (c && source[c] !== '\n') c -= 1; this.indentation = ''; - while ( true ) { // eslint-disable-line no-constant-condition + while (true) { + // eslint-disable-line no-constant-condition c += 1; const char = source[c]; - if ( char !== ' ' && char !== '\t' ) break; + if (char !== ' ' && char !== '\t') break; this.indentation += char; } @@ -102,81 +104,92 @@ export default class BlockStatement extends Node { // account for dedented class constructors 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, ''); } parent = parent.parent; } - if ( useOuter ) this.indentation += indentString; + if (useOuter) this.indentation += indentString; } return this.indentation; } - transpile ( code, transforms ) { + transpile(code, transforms) { const indentation = this.getIndentation(); let introStatementGenerators = []; - 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.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; } else { start = this.start + 1; @@ -184,100 +197,133 @@ export default class BlockStatement extends Node { let prefix = `\n${indentation}`; 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 ) { + 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 ]; - - if ( penultimateParam ) { - code.remove( penultimateParam ? penultimateParam.end : param.start, param.end ); + } 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 + ); } 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); } } }); } - 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 }); - - forStatement.aliases[ name ] = { + code.overwrite( + declaration.node.start, + declaration.node.end, + outerAlias, + { storeName: true } + ); + + forStatement.aliases[name] = { outer: outerAlias, 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 + }); } } @@ -285,16 +331,23 @@ export default class BlockStatement extends Node { } } - 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 }); - - for ( const identifier of declaration.instances ) { + code.overwrite( + declaration.node.start, + declaration.node.end, + alias, + { storeName: true } + ); + + 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 + }); } } } diff --git a/src/program/Node.js b/src/program/Node.js index 1b296772..5a65fd12 100644 --- a/src/program/Node.js +++ b/src/program/Node.js @@ -3,18 +3,24 @@ import keys from './keys.js'; // used for debugging, without the noise created by // 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; - - if ( Array.isArray( node[ key ] ) ) { - obj[ key ] = node[ key ].map( toJSON ); - } else if ( node[ key ] && node[ key ].toJSON ) { - obj[ key ] = node[ key ].toJSON(); + 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(); } else { - obj[ key ] = node[ key ]; + obj[key] = node[key]; } }); @@ -22,102 +28,102 @@ function toJSON ( node ) { } 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; } return node; } - contains ( node ) { - while ( node ) { - if ( node === this ) return true; + contains(node) { + while (node) { + if (node === this) return true; node = node.parent; } return false; } - 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; } return node; } - unparenthesize () { + unparenthesize() { let node = this; - while ( node.type === 'ParenthesizedExpression' ) { + while (node.type === 'ParenthesizedExpression') { node = node.expression; } return node; } - 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); } } } - 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); } } } diff --git a/src/program/Program.js b/src/program/Program.js index 73c24360..5a6065da 100644 --- a/src/program/Program.js +++ b/src/program/Program.js @@ -2,7 +2,7 @@ import MagicString from 'magic-string'; import BlockStatement from './BlockStatement.js'; import wrap from './wrap.js'; -export default function Program ( source, ast, transforms, options ) { +export default function Program(source, ast, transforms, options) { this.type = 'Root'; // options @@ -10,29 +10,29 @@ export default function Program ( source, ast, transforms, options ) { this.options = options; this.source = source; - this.magicString = new MagicString( source ); + this.magicString = new MagicString(source); this.ast = ast; this.depth = 0; - 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 { code: this.magicString.toString(), map: this.magicString.generateMap({ @@ -43,11 +43,11 @@ Program.prototype = { }; }, - findNearest () { + findNearest() { return null; }, - findScope () { + findScope() { return null; } }; diff --git a/src/program/Scope.js b/src/program/Scope.js index 5ed4a295..18f16643 100644 --- a/src/program/Scope.js +++ b/src/program/Scope.js @@ -1,92 +1,103 @@ import extractNames from './extractNames.js'; import reserved from '../utils/reserved.js'; -export default function Scope ( options ) { +export default function Scope(options) { options = options || {}; this.parent = options.parent; this.isBlockScope = !!options.block; 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); } } }, - 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); } this.consolidated = true; // TODO understand why this is necessary... seems bad }, - 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,}/, '_'); let name = base; let counter = 1; - 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)) + ); } }; diff --git a/src/program/extractNames.js b/src/program/extractNames.js index 088eae32..e9302d8f 100644 --- a/src/program/extractNames.js +++ b/src/program/extractNames.js @@ -1,35 +1,35 @@ -export default function extractNames ( node ) { +export default function extractNames(node) { const names = []; - extractors[ node.type ]( names, node ); + extractors[node.type](names, node); return names; } 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); } }; diff --git a/src/program/keys.js b/src/program/keys.js index 194ccf77..bb442af6 100644 --- a/src/program/keys.js +++ b/src/program/keys.js @@ -1,4 +1,4 @@ export default { - Program: [ 'body' ], + Program: ['body'], Literal: [] }; diff --git a/src/program/types/ArrayExpression.js b/src/program/types/ArrayExpression.js index 15c04dc4..c8e6304e 100644 --- a/src/program/types/ArrayExpression.js +++ b/src/program/types/ArrayExpression.js @@ -2,54 +2,69 @@ import Node from '../Node.js'; import spread, { isArguments } from '../../utils/spread.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(); } } } - 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, ')'); } } } - super.transpile( code, transforms ); + super.transpile(code, transforms); } } diff --git a/src/program/types/ArrowFunctionExpression.js b/src/program/types/ArrowFunctionExpression.js index 3fa9473a..b5ae9424 100644 --- a/src/program/types/ArrowFunctionExpression.js +++ b/src/program/types/ArrowFunctionExpression.js @@ -1,44 +1,45 @@ import Node from '../Node.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) { + 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 (this.params.length === 1 && this.start === this.params[0].start) { + 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); } } // Returns whether any transforms that will happen use `arguments` 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 + ); } } diff --git a/src/program/types/AssignmentExpression.js b/src/program/types/AssignmentExpression.js index 2a559b75..a80dc606 100644 --- a/src/program/types/AssignmentExpression.js +++ b/src/program/types/AssignmentExpression.js @@ -2,39 +2,41 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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]; const start = this.start; @@ -43,156 +45,160 @@ export default class AssignmentExpression extends Node { // easily do that while keeping the order of the output // predictable. 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); // Walk `pattern`, generating code that assigns the value in // `ref` to it. When `mayDuplicate` is false, the function // 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}` ); - } - - else if ( pattern.type === 'AssignmentPattern' ) { - if ( pattern.left.type === 'Identifier' ) { - code.remove( pattern.start, pattern.right.start ); + 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); 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; } let c = pattern.start; - elements.forEach( ( element, i ) => { + elements.forEach((element, i) => { if (!element) return; code.remove(c, element.start); c = element.end; - 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); } }); code.remove(c, pattern.end); } - } - - 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}`; - - 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}` ); + 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}`); ref = temp; } let c = pattern.start; - 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}`; code.remove(c, prop.value.start); c = prop.end; - destructure( prop.value, value, false ); + destructure(prop.value, value, false); }); code.remove(c, pattern.end); } - } - - 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; }; // first, the easy part – `**=` -> `=` 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); // how we do the next part depends on a number of factors – whether // this is a top-level statement, and whether we're updating a @@ -201,93 +207,106 @@ export default class AssignmentExpression extends Node { const left = this.left.unparenthesize(); - 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; let needsObjectVar = false; let property; let needsPropertyVar = 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}]` ); - } - - 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 ); - - code.appendLeft( left.object.end, `[${property}]` ); - code.remove( left.object.end, left.property.start ); - code.remove( left.property.end, left.end ); + 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); + + 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 ( 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) declarators.push(object); + if (needsPropertyVar) declarators.push(property); + + if (declarators.length) { + code.prependRight( + statement.start, + `var ${declarators.join(', ')};\n${i0}` + ); } - else if ( needsObjectVar ) { - code.prependRight( left.start, `( ${object} = ` ); - code.appendLeft( left.object.end, `, ${object}` ); - } - - else if ( needsPropertyVar ) { - code.prependRight( left.property.start, `( ${property} = ` ); - code.appendLeft( left.property.end, `, ` ); - code.move( left.property.start, left.property.end, left.start ); - - code.overwrite( left.object.end, left.property.start, `[${property}]` ); - code.remove( left.property.end, left.end ); + if (needsObjectVar && needsPropertyVar) { + code.prependRight(left.start, `( ${object} = `); + code.overwrite( + left.object.end, + left.property.start, + `, ${property} = ` + ); + code.overwrite( + left.property.end, + left.end, + `, ${object}[${property}]` + ); + } else if (needsObjectVar) { + code.prependRight(left.start, `( ${object} = `); + code.appendLeft(left.object.end, `, ${object}`); + } else if (needsPropertyVar) { + code.prependRight(left.property.start, `( ${property} = `); + code.appendLeft(left.property.end, `, `); + code.move(left.property.start, left.property.end, left.start); + + code.overwrite(left.object.end, left.property.start, `[${property}]`); + code.remove(left.property.end, left.end); } - if ( needsPropertyVar ) { - code.appendLeft( this.end, ` )` ); + 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, ` )`); } } diff --git a/src/program/types/BinaryExpression.js b/src/program/types/BinaryExpression.js index d755677d..ea778a30 100644 --- a/src/program/types/BinaryExpression.js +++ b/src/program/types/BinaryExpression.js @@ -1,12 +1,12 @@ 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); } } diff --git a/src/program/types/BreakStatement.js b/src/program/types/BreakStatement.js index 4f9a207a..748fe611 100644 --- a/src/program/types/BreakStatement.js +++ b/src/program/types/BreakStatement.js @@ -3,20 +3,24 @@ import CompileError from '../../utils/CompileError.js'; import { loopStatement } from '../../utils/patterns.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; 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'`); } } } diff --git a/src/program/types/CallExpression.js b/src/program/types/CallExpression.js index eaa50b71..a37a6f8b 100644 --- a/src/program/types/CallExpression.js +++ b/src/program/types/CallExpression.js @@ -2,97 +2,105 @@ import Node from '../Node.js'; import spread, { isArguments } from '../../utils/spread.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(); } } } - 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; let context; const firstArgument = this.arguments[0]; - 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};`); } } else { context = 'void 0'; } - 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, ' )'); } } } - super.transpile( code, transforms ); + super.transpile(code, transforms); } } diff --git a/src/program/types/ClassBody.js b/src/program/types/ClassBody.js index edc5e96a..8a917698 100644 --- a/src/program/types/ClassBody.js +++ b/src/program/types/ClassBody.js @@ -4,183 +4,234 @@ import reserved from '../../utils/reserved.js'; // TODO this code is pretty wild, tidy it up 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]; let introBlock = ''; let outroBlock = ''; - 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};`; - - if ( constructor ) { + 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) { 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}` : ''); inheritanceBlock = fn + inheritanceBlock; introBlock += inheritanceBlock + `\n\n${i0}`; } - } 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}`; introBlock += fn; } - const scope = this.findScope( false ); + const scope = this.findScope(false); let prototypeGettersAndSetters = []; let staticGettersAndSetters = []; let prototypeAccessors; let staticAccessors; - 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); } const isAccessor = method.kind !== 'method'; let lhs; 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); } // when method name is a string or a number let's pretend it's a computed method let fake_computed = false; - if ( ! method.computed && method.key.type === 'Literal' ) { + if (!method.computed && method.key.type === 'Literal') { fake_computed = true; 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'); 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; } } - 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 ); - - code.prependRight( method.start, lhs ); + 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); + + 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); } } diff --git a/src/program/types/ClassDeclaration.js b/src/program/types/ClassDeclaration.js index d3bb8e77..dbd9b2b6 100644 --- a/src/program/types/ClassDeclaration.js +++ b/src/program/types/ClassDeclaration.js @@ -2,61 +2,65 @@ import Node from '../Node.js'; import deindent from '../../utils/deindent.js'; export default class ClassDeclaration extends Node { - initialise ( transforms ) { + initialise(transforms) { this.name = this.id.name; - this.findScope( true ).addDeclaration( this.id, 'class' ); + this.findScope(true).addDeclaration(this.id, 'class'); - 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'); const i0 = this.getIndentation(); const i1 = i0 + code.getIndentString(); // if this is an export default statement, we have to move the export to // 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 syntheticDefaultExport = + this.parent.type === 'ExportDefaultDeclaration' + ? `\n\n${i0}export default ${this.id.name};` + : ''; - if ( syntheticDefaultExport ) code.remove( this.parent.start, this.start ); + if (syntheticDefaultExport) code.remove(this.parent.start, this.start); - code.overwrite( this.start, this.id.start, 'var ' ); + code.overwrite(this.start, this.id.start, 'var '); - 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(this.id.end, this.superClass.start); + code.appendLeft(this.id.end, ` = (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(this.id.end, 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 (this.id.end === this.body.start) { + code.appendLeft(this.id.end, ' = '); } else { - code.overwrite( this.id.end, this.body.start, ' = ' ); + code.overwrite(this.id.end, 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 ); + 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); } } } diff --git a/src/program/types/ClassExpression.js b/src/program/types/ClassExpression.js index e05f7334..e1454c9c 100644 --- a/src/program/types/ClassExpression.js +++ b/src/program/types/ClassExpression.js @@ -1,45 +1,47 @@ 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' ); - - super.initialise( transforms ); + 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'); + + 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'); const i0 = this.getIndentation(); const i1 = i0 + code.getIndentString(); - 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); } } } diff --git a/src/program/types/ContinueStatement.js b/src/program/types/ContinueStatement.js index ad38877c..efd2ba18 100644 --- a/src/program/types/ContinueStatement.js +++ b/src/program/types/ContinueStatement.js @@ -3,11 +3,15 @@ import CompileError from '../../utils/CompileError.js'; import { loopStatement } from '../../utils/patterns.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'); } } } diff --git a/src/program/types/ExportDefaultDeclaration.js b/src/program/types/ExportDefaultDeclaration.js index 97bf6c98..883fc5fa 100644 --- a/src/program/types/ExportDefaultDeclaration.js +++ b/src/program/types/ExportDefaultDeclaration.js @@ -2,8 +2,9 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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); } } diff --git a/src/program/types/ExportNamedDeclaration.js b/src/program/types/ExportNamedDeclaration.js index 86e49530..24357887 100644 --- a/src/program/types/ExportNamedDeclaration.js +++ b/src/program/types/ExportNamedDeclaration.js @@ -2,8 +2,9 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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); } } diff --git a/src/program/types/ForInStatement.js b/src/program/types/ForInStatement.js index 07e63d7a..c58a3482 100644 --- a/src/program/types/ForInStatement.js +++ b/src/program/types/ForInStatement.js @@ -2,21 +2,33 @@ import LoopStatement from './shared/LoopStatement.js'; import extractNames from '../extractNames.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); } } diff --git a/src/program/types/ForOfStatement.js b/src/program/types/ForOfStatement.js index b630d3b3..c8229f96 100644 --- a/src/program/types/ForOfStatement.js +++ b/src/program/types/ForOfStatement.js @@ -3,69 +3,76 @@ import CompileError from '../../utils/CompileError.js'; import destructure from '../../utils/destructure.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); } return; } - 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}}`); } const bodyStart = this.body.body[0].start; - 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}`); } } } diff --git a/src/program/types/ForStatement.js b/src/program/types/ForStatement.js index 2beacef8..3446ebb7 100644 --- a/src/program/types/ForStatement.js +++ b/src/program/types/ForStatement.js @@ -2,37 +2,53 @@ import LoopStatement from './shared/LoopStatement.js'; import extractNames from '../extractNames.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}`)}` + ); } } } - super.transpile( code, transforms ); + super.transpile(code, transforms); } } diff --git a/src/program/types/FunctionDeclaration.js b/src/program/types/FunctionDeclaration.js index 2f65aad7..1a2cbcf1 100644 --- a/src/program/types/FunctionDeclaration.js +++ b/src/program/types/FunctionDeclaration.js @@ -2,14 +2,14 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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); } this.body.createScope(); - this.findScope( true ).addDeclaration( this.id, 'function' ); - super.initialise( transforms ); + this.findScope(true).addDeclaration(this.id, 'function'); + super.initialise(transforms); } } diff --git a/src/program/types/FunctionExpression.js b/src/program/types/FunctionExpression.js index 62dd216d..ebaebc9f 100644 --- a/src/program/types/FunctionExpression.js +++ b/src/program/types/FunctionExpression.js @@ -2,57 +2,59 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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); } this.body.createScope(); - 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); const parent = this.parent; let methodName; - 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 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: // https://gitlab.com/Rich-Harris/buble/issues/154 // change parameter name when same as method name 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; } diff --git a/src/program/types/Identifier.js b/src/program/types/Identifier.js index c49f7660..e71d7783 100644 --- a/src/program/types/Identifier.js +++ b/src/program/types/Identifier.js @@ -3,41 +3,51 @@ import isReference from '../../utils/isReference.js'; import { loopStatement } from '../../utils/patterns.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(); } } - 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 + }); } } } diff --git a/src/program/types/IfStatement.js b/src/program/types/IfStatement.js index 4abe109b..bdeebb42 100644 --- a/src/program/types/IfStatement.js +++ b/src/program/types/IfStatement.js @@ -1,24 +1,29 @@ 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); } } diff --git a/src/program/types/ImportDeclaration.js b/src/program/types/ImportDeclaration.js index 656f3b82..b94458d8 100644 --- a/src/program/types/ImportDeclaration.js +++ b/src/program/types/ImportDeclaration.js @@ -2,8 +2,9 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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); } } diff --git a/src/program/types/ImportDefaultSpecifier.js b/src/program/types/ImportDefaultSpecifier.js index f1505d0a..0f2a9f43 100644 --- a/src/program/types/ImportDefaultSpecifier.js +++ b/src/program/types/ImportDefaultSpecifier.js @@ -1,8 +1,8 @@ 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); } } diff --git a/src/program/types/ImportSpecifier.js b/src/program/types/ImportSpecifier.js index 1e99f3fe..121d630a 100644 --- a/src/program/types/ImportSpecifier.js +++ b/src/program/types/ImportSpecifier.js @@ -1,8 +1,8 @@ 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); } } diff --git a/src/program/types/JSXAttribute.js b/src/program/types/JSXAttribute.js index 9e21293c..fe52338c 100644 --- a/src/program/types/JSXAttribute.js +++ b/src/program/types/JSXAttribute.js @@ -2,19 +2,19 @@ import Node from '../Node.js'; const hasDashes = val => /-/.test(val); -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; // Overwrite equals sign if value is present. const end = this.value ? this.value.start : this.name.end; - 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); } } diff --git a/src/program/types/JSXClosingElement.js b/src/program/types/JSXClosingElement.js index e3e03fe9..d2cb44a3 100644 --- a/src/program/types/JSXClosingElement.js +++ b/src/program/types/JSXClosingElement.js @@ -1,22 +1,27 @@ 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]; // omit space before closing paren if // a) this is on a separate line, or // 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 ? ' )' : ')'); } } diff --git a/src/program/types/JSXElement.js b/src/program/types/JSXElement.js index 60a26f47..4cb4de13 100644 --- a/src/program/types/JSXElement.js +++ b/src/program/types/JSXElement.js @@ -1,46 +1,50 @@ 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.value) || !/\n/.test(child.value); }); - 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.value, i === children.length - 1); + code.overwrite(child.start, child.end, str); } c = child.end; diff --git a/src/program/types/JSXExpressionContainer.js b/src/program/types/JSXExpressionContainer.js index e45e66d3..f9f3a813 100644 --- a/src/program/types/JSXExpressionContainer.js +++ b/src/program/types/JSXExpressionContainer.js @@ -1,10 +1,10 @@ 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); } } diff --git a/src/program/types/JSXOpeningElement.js b/src/program/types/JSXOpeningElement.js index 16286e40..922083e7 100644 --- a/src/program/types/JSXOpeningElement.js +++ b/src/program/types/JSXOpeningElement.js @@ -2,23 +2,25 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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, `'`); const len = this.attributes.length; let c = this.name.end; - 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; break; } @@ -26,26 +28,24 @@ export default class JSXOpeningElement extends Node { c = this.attributes[0].end; - 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, ' }'); } } @@ -54,14 +54,19 @@ export default class JSXOpeningElement extends Node { let after; 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 = ')'; } } else { @@ -69,20 +74,20 @@ export default class JSXOpeningElement extends Node { after = ' }'; } - 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); } } } diff --git a/src/program/types/JSXSpreadAttribute.js b/src/program/types/JSXSpreadAttribute.js index 0a680766..cd11a610 100644 --- a/src/program/types/JSXSpreadAttribute.js +++ b/src/program/types/JSXSpreadAttribute.js @@ -1,10 +1,10 @@ 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); } } diff --git a/src/program/types/Literal.js b/src/program/types/Literal.js index 6d9dded7..a2f5692c 100644 --- a/src/program/types/Literal.js +++ b/src/program/types/Literal.js @@ -3,31 +3,40 @@ import CompileError from '../../utils/CompileError.js'; import rewritePattern from 'regexpu-core'; 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, 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 + } + ); } } } diff --git a/src/program/types/MemberExpression.js b/src/program/types/MemberExpression.js index f5f76c75..b254c485 100644 --- a/src/program/types/MemberExpression.js +++ b/src/program/types/MemberExpression.js @@ -2,12 +2,12 @@ import Node from '../Node.js'; import reserved from '../../utils/reserved.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); } } diff --git a/src/program/types/NewExpression.js b/src/program/types/NewExpression.js index 4e6c942e..8d33c066 100644 --- a/src/program/types/NewExpression.js +++ b/src/program/types/NewExpression.js @@ -2,36 +2,49 @@ import Node from '../Node.js'; import spread, { isArguments } from '../../utils/spread.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(); 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); } } diff --git a/src/program/types/ObjectExpression.js b/src/program/types/ObjectExpression.js index 50b4b497..9f620121 100644 --- a/src/program/types/ObjectExpression.js +++ b/src/program/types/ObjectExpression.js @@ -2,8 +2,8 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.js'; export default class ObjectExpression extends Node { - transpile ( code, transforms ) { - super.transpile( code, transforms ); + transpile(code, transforms) { + super.transpile(code, transforms); let firstPropertyStart = this.start + 1; let regularPropertyCount = 0; @@ -12,39 +12,50 @@ export default class ObjectExpression extends Node { let firstSpreadProperty = null; let firstComputedProperty = null; - 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; } } - 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, '}'); } } } @@ -52,52 +63,78 @@ export default class ObjectExpression extends Node { // wrap the whole thing in Object.assign 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(); let isSimpleAssignment; let name; - 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; 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; const start = firstPropertyStart; const end = this.end; - if ( isSimpleAssignment ) { + if (isSimpleAssignment) { // ??? } else { - if ( firstSpreadProperty === null || firstComputedProperty < firstSpreadProperty ) { - name = this.findScope( true ).createIdentifier( 'obj' ); + if ( + firstSpreadProperty === null || + firstComputedProperty < firstSpreadProperty + ) { + name = this.findScope(true).createIdentifier('obj'); - code.prependRight( this.start, `( ${name} = ` ); + code.prependRight(this.start, `( ${name} = `); } else name = null; // We don't actually need this variable } @@ -106,94 +143,104 @@ export default class ObjectExpression extends Node { let sawNonComputedProperty = false; let isFirst = true; - 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.findScope(true).createIdentifier('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); } } 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};` ); + const statement = this.findNearest(/(?:Statement|Declaration)$/); + code.appendLeft(statement.end, `\n${i0}var ${name};`); lastComputedProp = null; 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; } // Clean up some extranous whitespace 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} )` ); + if (!isSimpleAssignment && name) { + code.appendLeft(lastComputedProp.end, `, ${name} )`); - const statement = this.findNearest( /(?:Statement|Declaration)$/ ); - code.appendLeft( statement.end, `\n${i0}var ${name};` ); + const statement = this.findNearest(/(?:Statement|Declaration)$/); + code.appendLeft(statement.end, `\n${i0}var ${name};`); } } } diff --git a/src/program/types/Property.js b/src/program/types/Property.js index abbca3a0..6ea9fbc7 100644 --- a/src/program/types/Property.js +++ b/src/program/types/Property.js @@ -2,39 +2,51 @@ import Node from '../Node.js'; import reserved from '../../utils/reserved.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 { name = this.key.name; } } else { - name = this.findScope( true ).createIdentifier( this.key.value ); + name = this.findScope(true).createIdentifier(this.key.value); } 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, `'`); } } } diff --git a/src/program/types/ReturnStatement.js b/src/program/types/ReturnStatement.js index e215ec65..96208634 100644 --- a/src/program/types/ReturnStatement.js +++ b/src/program/types/ReturnStatement.js @@ -2,27 +2,31 @@ import Node from '../Node.js'; import { loopStatement } from '../../utils/patterns.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; 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, ' {}'); } } } diff --git a/src/program/types/SpreadElement.js b/src/program/types/SpreadElement.js index 82ba8705..891a64ee 100644 --- a/src/program/types/SpreadElement.js +++ b/src/program/types/SpreadElement.js @@ -1,12 +1,12 @@ 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); } } diff --git a/src/program/types/Super.js b/src/program/types/Super.js index 0c4e13f0..d26e8738 100644 --- a/src/program/types/Super.js +++ b/src/program/types/Super.js @@ -3,65 +3,84 @@ import CompileError from '../../utils/CompileError.js'; import { loopStatement } from '../../utils/patterns.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' ); - - 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 ); - - 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 ); + 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'); + + if (!this.superClassName) + throw new CompileError('super used in base class', this); + + 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 + ); } this.isMember = this.parent.type === 'MemberExpression'; - 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(); } } } - 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'); } const thisAlias = this.thisAlias || 'this'; - 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}`); } } } diff --git a/src/program/types/TaggedTemplateExpression.js b/src/program/types/TaggedTemplateExpression.js index 18641a6c..987aabe7 100644 --- a/src/program/types/TaggedTemplateExpression.js +++ b/src/program/types/TaggedTemplateExpression.js @@ -2,36 +2,50 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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, ', '); } lastIndex = node.end; }); - code.overwrite( lastIndex, this.end, ')' ); + code.overwrite(lastIndex, this.end, ')'); } - super.transpile( code, transforms ); + super.transpile(code, transforms); } } diff --git a/src/program/types/TemplateElement.js b/src/program/types/TemplateElement.js index b9658b59..e08965d3 100644 --- a/src/program/types/TemplateElement.js +++ b/src/program/types/TemplateElement.js @@ -1,7 +1,7 @@ import Node from '../Node.js'; export default class TemplateElement extends Node { - initialise () { - this.program.indentExclusionElements.push( this ); + initialise() { + this.program.indentExclusionElements.push(this); } } diff --git a/src/program/types/TemplateLiteral.js b/src/program/types/TemplateLiteral.js index 9318a208..b89961f7 100644 --- a/src/program/types/TemplateLiteral.js +++ b/src/program/types/TemplateLiteral.js @@ -1,18 +1,22 @@ 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; // exclude all empty strings not at the head return !i; @@ -22,47 +26,55 @@ export default class TemplateLiteral extends Node { // if it's the empty string, but only if the second and // third elements aren't both expressions (since they maybe // 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(); } } - 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, ')'); } lastIndex = node.end; }); - if ( parenthesise ) code.appendLeft( lastIndex, ')' ); - code.remove( lastIndex, this.end ); + if (parenthesise) code.appendLeft(lastIndex, ')'); + code.remove(lastIndex, this.end); } } } diff --git a/src/program/types/ThisExpression.js b/src/program/types/ThisExpression.js index 332f1825..b672b7b3 100644 --- a/src/program/types/ThisExpression.js +++ b/src/program/types/ThisExpression.js @@ -2,23 +2,27 @@ import Node from '../Node.js'; import { loopStatement } from '../../utils/patterns.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(); } } } - 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, contentOnly: true }); diff --git a/src/program/types/UpdateExpression.js b/src/program/types/UpdateExpression.js index 8020ebfe..a094db80 100644 --- a/src/program/types/UpdateExpression.js +++ b/src/program/types/UpdateExpression.js @@ -2,20 +2,26 @@ import Node from '../Node.js'; import CompileError from '../../utils/CompileError.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); } } diff --git a/src/program/types/VariableDeclaration.js b/src/program/types/VariableDeclaration.js index bcab2e41..38563890 100644 --- a/src/program/types/VariableDeclaration.js +++ b/src/program/types/VariableDeclaration.js @@ -3,68 +3,83 @@ import destructure from '../../utils/destructure.js'; import { loopStatement } from '../../utils/patterns.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; 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); }); } @@ -72,14 +87,12 @@ export default class VariableDeclaration extends Node { lastDeclaratorIsPattern = declarator.id.type !== 'Identifier'; }); - 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); }); } } diff --git a/src/program/types/VariableDeclarator.js b/src/program/types/VariableDeclarator.js index 40eeee7c..4f7dc888 100644 --- a/src/program/types/VariableDeclarator.js +++ b/src/program/types/VariableDeclarator.js @@ -1,35 +1,43 @@ 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 + ); } } diff --git a/src/program/types/shared/LoopStatement.js b/src/program/types/shared/LoopStatement.js index c2e063bc..1e6154f3 100644 --- a/src/program/types/shared/LoopStatement.js +++ b/src/program/types/shared/LoopStatement.js @@ -1,91 +1,105 @@ 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(); 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; break; } } - if ( this.shouldRewriteAsFunction ) break; + if (this.shouldRewriteAsFunction) break; } } } - 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); } } diff --git a/src/program/types/shared/ModuleDeclaration.js b/src/program/types/shared/ModuleDeclaration.js index ed4eb8d2..0022f9ed 100644 --- a/src/program/types/shared/ModuleDeclaration.js +++ b/src/program/types/shared/ModuleDeclaration.js @@ -2,8 +2,9 @@ import Node from '../../Node.js'; import CompileError from '../../../utils/CompileError.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); } } diff --git a/src/program/wrap.js b/src/program/wrap.js index 1e0a130c..c9ea7878 100644 --- a/src/program/wrap.js +++ b/src/program/wrap.js @@ -13,42 +13,45 @@ const statementsWithBlocks = { ArrowFunctionExpression: 'body' }; -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; } // with e.g. shorthand properties, key and value are // 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 }; } - 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; } diff --git a/src/utils/CompileError.js b/src/utils/CompileError.js index 0f08beb2..116721d3 100644 --- a/src/utils/CompileError.js +++ b/src/utils/CompileError.js @@ -2,24 +2,29 @@ import locate from './locate.js'; import getSnippet from './getSnippet.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}`; } } diff --git a/src/utils/array.js b/src/utils/array.js index 70dbe6cc..d72e4b9a 100644 --- a/src/utils/array.js +++ b/src/utils/array.js @@ -1,11 +1,11 @@ -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; } return -1; } -export function find ( array, fn ) { - return array[ findIndex( array, fn ) ]; +export function find(array, fn) { + return array[findIndex(array, fn)]; } diff --git a/src/utils/deindent.js b/src/utils/deindent.js index 6b49f829..8b6c5ee8 100644 --- a/src/utils/deindent.js +++ b/src/utils/deindent.js @@ -2,7 +2,7 @@ // not its current edited state. // That's not a problem for the way that it's currently used, but it could // be in future... -export default function deindent ( node, code ) { +export default function deindent(node, code) { const start = node.start; const end = node.end; @@ -10,19 +10,21 @@ export default function deindent ( node, code ) { const indentStrLen = indentStr.length; const indentStart = start - indentStrLen; - 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); } } } diff --git a/src/utils/destructure.js b/src/utils/destructure.js index d1cc4d57..ab4748ee 100644 --- a/src/utils/destructure.js +++ b/src/utils/destructure.js @@ -7,88 +7,168 @@ const handlers = { ObjectPattern: destructureObjectPattern }; -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; - - if ( element.type === 'RestElement' ) { - handleProperty( code, scope, c, element.argument, `${ref}.slice(${i})`, inline, statementGenerators ); + node.elements.forEach((element, i) => { + if (!element) return; + + 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 + ); } 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; } @@ -97,102 +177,161 @@ function handleProperty ( code, scope, c, node, value, inline, statementGenerato const isIdentifier = node.left.type === 'Identifier'; - 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 + ); } break; } 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.overwrite( node.start, c = node.start + 1, `${prefix}var ${ref} = ${value}${suffix}` ); - code.move( node.start, c, start ); + 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); }); } - destructureObjectPattern( code, scope, node, ref, inline, statementGenerators ); + destructureObjectPattern( + code, + scope, + node, + ref, + inline, + statementGenerators + ); 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; - - if ( element.type === 'RestElement' ) { - handleProperty( code, scope, c, element.argument, `${ref}.slice(${i})`, inline, statementGenerators ); + node.elements.forEach((element, i) => { + if (!element) return; + + 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 + ); } 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 + ); } c = element.end; } - code.remove( c, node.end ); + code.remove(c, node.end); break; } default: { - throw new Error( `Unexpected node type in destructuring (${node.type})` ); + throw new Error(`Unexpected node type in destructuring (${node.type})`); } } } diff --git a/src/utils/getSnippet.js b/src/utils/getSnippet.js index 950a5155..a114c466 100644 --- a/src/utils/getSnippet.js +++ b/src/utils/getSnippet.js @@ -1,30 +1,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; } diff --git a/src/utils/isReference.js b/src/utils/isReference.js index 2084681a..f0cbcb5e 100644 --- a/src/utils/isReference.js +++ b/src/utils/isReference.js @@ -1,36 +1,40 @@ -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; } // 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; return true; } diff --git a/src/utils/locate.js b/src/utils/locate.js index 03ebc423..bd10b00c 100644 --- a/src/utils/locate.js +++ b/src/utils/locate.js @@ -1,20 +1,20 @@ -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; var lineStart = 0; var i; - 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 }; } lineStart = lineEnd; } - throw new Error( 'Could not determine location of character' ); + throw new Error('Could not determine location of character'); } diff --git a/src/utils/reserved.js b/src/utils/reserved.js index fa3e8380..7268cbef 100644 --- a/src/utils/reserved.js +++ b/src/utils/reserved.js @@ -1,5 +1,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; diff --git a/src/utils/spread.js b/src/utils/spread.js index 1c0cb39e..2026a925 100644 --- a/src/utils/spread.js +++ b/src/utils/spread.js @@ -1,57 +1,67 @@ -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 + ); } firstSpreadIndex = i; } } - 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, ']'); } } return true; // true indicates some spread elements } - 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, ']'); } } } diff --git a/test/cli/compiles-directory/expected/bar.js b/test/cli/compiles-directory/expected/bar.js index a6d15072..02838e67 100644 --- a/test/cli/compiles-directory/expected/bar.js +++ b/test/cli/compiles-directory/expected/bar.js @@ -1,2 +1,2 @@ console.log( 'bar' ); -//# sourceMappingURL=bar.js.map +//# sourceMappingURL=bar.js.map \ No newline at end of file diff --git a/test/cli/compiles-directory/expected/foo.js b/test/cli/compiles-directory/expected/foo.js index 380852dc..27d0cb8e 100644 --- a/test/cli/compiles-directory/expected/foo.js +++ b/test/cli/compiles-directory/expected/foo.js @@ -1,2 +1,3 @@ -console.log( 'foo' ); -//# sourceMappingURL=foo.js.map +console.log('foo'); + +//# sourceMappingURL=foo.js.map \ No newline at end of file diff --git a/test/cli/compiles-directory/expected/foo.js.map b/test/cli/compiles-directory/expected/foo.js.map index 71906e75..412da24f 100644 --- a/test/cli/compiles-directory/expected/foo.js.map +++ b/test/cli/compiles-directory/expected/foo.js.map @@ -1 +1 @@ -{"version":3,"file":"foo.js","sources":["../src/foo.js"],"sourcesContent":["console.log( 'foo' );"],"names":[],"mappings":"AAAA,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE"} +{"version":3,"file":"foo.js","sources":["../src/foo.js"],"sourcesContent":["console.log('foo');\n"],"names":[],"mappings":"AAAA,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;"} \ No newline at end of file diff --git a/test/cli/compiles-directory/src/foo.js b/test/cli/compiles-directory/src/foo.js index db1b7072..81afa315 100644 --- a/test/cli/compiles-directory/src/foo.js +++ b/test/cli/compiles-directory/src/foo.js @@ -1 +1 @@ -console.log( 'foo' ); \ No newline at end of file +console.log('foo'); diff --git a/test/cli/creates-inline-sourcemap/expected/output.js b/test/cli/creates-inline-sourcemap/expected/output.js index 1f48bc45..ae45cb9f 100644 --- a/test/cli/creates-inline-sourcemap/expected/output.js +++ b/test/cli/creates-inline-sourcemap/expected/output.js @@ -1,2 +1,3 @@ var answer = function () { return 42; }; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0cHV0LmpzIiwic291cmNlcyI6WyIuLi9pbnB1dC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBhbnN3ZXIgPSAoKSA9PiA0MjsiXSwibmFtZXMiOlsiY29uc3QiXSwibWFwcGluZ3MiOiJBQUFBQSxHQUFLLENBQUMsTUFBTSxZQUFHLEdBQUcsU0FBRyxLQUFFIn0= \ No newline at end of file + +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0cHV0LmpzIiwic291cmNlcyI6WyIuLi9pbnB1dC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBhbnN3ZXIgPSAoKSA9PiA0MjtcbiJdLCJuYW1lcyI6WyJjb25zdCJdLCJtYXBwaW5ncyI6IkFBQUFBLEdBQUssQ0FBQyxNQUFNLFlBQUcsR0FBRyxTQUFHLEtBQUUsQ0FBQzsifQ== \ No newline at end of file diff --git a/test/cli/creates-inline-sourcemap/input.js b/test/cli/creates-inline-sourcemap/input.js index 1a3ed38b..e2ce27d6 100644 --- a/test/cli/creates-inline-sourcemap/input.js +++ b/test/cli/creates-inline-sourcemap/input.js @@ -1 +1 @@ -const answer = () => 42; \ No newline at end of file +const answer = () => 42; diff --git a/test/cli/creates-sourcemap/expected/output.js b/test/cli/creates-sourcemap/expected/output.js index 7e74c479..2badd3fe 100644 --- a/test/cli/creates-sourcemap/expected/output.js +++ b/test/cli/creates-sourcemap/expected/output.js @@ -1,2 +1,3 @@ var answer = function () { return 42; }; -//# sourceMappingURL=output.js.map + +//# sourceMappingURL=output.js.map \ No newline at end of file diff --git a/test/cli/creates-sourcemap/expected/output.js.map b/test/cli/creates-sourcemap/expected/output.js.map index b1afab63..b549e153 100644 --- a/test/cli/creates-sourcemap/expected/output.js.map +++ b/test/cli/creates-sourcemap/expected/output.js.map @@ -1 +1 @@ -{"version":3,"file":"output.js","sources":["../input.js"],"sourcesContent":["const answer = () => 42;"],"names":["const"],"mappings":"AAAAA,GAAK,CAAC,MAAM,YAAG,GAAG,SAAG,KAAE"} \ No newline at end of file +{"version":3,"file":"output.js","sources":["../input.js"],"sourcesContent":["const answer = () => 42;\n"],"names":["const"],"mappings":"AAAAA,GAAK,CAAC,MAAM,YAAG,GAAG,SAAG,KAAE,CAAC;"} \ No newline at end of file diff --git a/test/cli/creates-sourcemap/input.js b/test/cli/creates-sourcemap/input.js index 1a3ed38b..e2ce27d6 100644 --- a/test/cli/creates-sourcemap/input.js +++ b/test/cli/creates-sourcemap/input.js @@ -1 +1 @@ -const answer = () => 42; \ No newline at end of file +const answer = () => 42; diff --git a/test/cli/supports-jsx-pragma-comment/expected/output.js b/test/cli/supports-jsx-pragma-comment/expected/output.js index db30e6f9..71766d16 100644 --- a/test/cli/supports-jsx-pragma-comment/expected/output.js +++ b/test/cli/supports-jsx-pragma-comment/expected/output.js @@ -1,2 +1,2 @@ /* @jsx customPragma */ -var div = customPragma( 'div', null, "Hello" ) +var div = customPragma( 'div', null, "Hello" ); diff --git a/test/cli/supports-jsx-pragma-comment/input.js b/test/cli/supports-jsx-pragma-comment/input.js index 356d281a..d3b39367 100644 --- a/test/cli/supports-jsx-pragma-comment/input.js +++ b/test/cli/supports-jsx-pragma-comment/input.js @@ -1,2 +1,2 @@ /* @jsx customPragma */ -var div =
Hello
+var div =
Hello
; diff --git a/test/cli/supports-jsx-pragma/expected/output.js b/test/cli/supports-jsx-pragma/expected/output.js index 1175b687..2b4e202c 100644 --- a/test/cli/supports-jsx-pragma/expected/output.js +++ b/test/cli/supports-jsx-pragma/expected/output.js @@ -1 +1 @@ -var img = NotReact.createElement( 'img', { src: 'foo.gif' }); +var img = NotReact.createElement( 'img', { src: "foo.gif" }); diff --git a/test/cli/supports-jsx-pragma/input.js b/test/cli/supports-jsx-pragma/input.js index fe2d823b..645a5069 100644 --- a/test/cli/supports-jsx-pragma/input.js +++ b/test/cli/supports-jsx-pragma/input.js @@ -1 +1 @@ -var img = ; +var img = ; diff --git a/test/cli/writes-to-stdout/expected/output.js b/test/cli/writes-to-stdout/expected/output.js index ed311672..4a6c09d2 100644 --- a/test/cli/writes-to-stdout/expected/output.js +++ b/test/cli/writes-to-stdout/expected/output.js @@ -1 +1,2 @@ var answer = function () { return 42; }; + diff --git a/test/samples/arrow-functions.js b/test/samples/arrow-functions.js index eb81ec72..45ae20dd 100644 --- a/test/samples/arrow-functions.js +++ b/test/samples/arrow-functions.js @@ -175,7 +175,8 @@ module.exports = [ }, { - description: 'handles standalone arrow function expression statement within a function', + description: + 'handles standalone arrow function expression statement within a function', input: ` function no_op () { @@ -189,7 +190,8 @@ module.exports = [ }, { - description: 'are transformed even if disabled if they have a transpiled spread parameter', + description: + 'are transformed even if disabled if they have a transpiled spread parameter', options: { transforms: { arrow: false, spreadRest: true } }, @@ -203,6 +205,5 @@ module.exports = [ return console.log( args ); };` - } ]; diff --git a/test/samples/async.js b/test/samples/async.js index a75be1b9..c98bb529 100644 --- a/test/samples/async.js +++ b/test/samples/async.js @@ -6,7 +6,6 @@ module.exports = [ ({async, foo})`, output: ` - ({async: async, foo: foo})`, + ({async: async, foo: foo})` } - ]; diff --git a/test/samples/classes-no-named-function-expressions.js b/test/samples/classes-no-named-function-expressions.js index 20543fb5..b3be24c6 100644 --- a/test/samples/classes-no-named-function-expressions.js +++ b/test/samples/classes-no-named-function-expressions.js @@ -42,7 +42,8 @@ module.exports = [ }, { - description: 'transpiles a class declaration without a constructor function', + description: + 'transpiles a class declaration without a constructor function', options: { namedFunctionExpressions: false }, input: ` @@ -236,7 +237,10 @@ module.exports = [ { description: 'transpiles export default class', - options: { transforms: { moduleExport: false }, namedFunctionExpressions: false }, + options: { + transforms: { moduleExport: false }, + namedFunctionExpressions: false + }, input: ` export default class Foo { @@ -253,7 +257,10 @@ module.exports = [ { description: 'transpiles export default subclass', - options: { transforms: { moduleExport: false }, namedFunctionExpressions: false }, + options: { + transforms: { moduleExport: false }, + namedFunctionExpressions: false + }, input: ` export default class Foo extends Bar { @@ -280,7 +287,10 @@ module.exports = [ { description: 'transpiles export default subclass with subsequent statement', - options: { transforms: { moduleExport: false }, namedFunctionExpressions: false }, + options: { + transforms: { moduleExport: false }, + namedFunctionExpressions: false + }, input: ` export default class Foo extends Bar { @@ -354,7 +364,8 @@ module.exports = [ }, { - description: 'transpiles an anonymous class expression with a non-constructor method', + description: + 'transpiles an anonymous class expression with a non-constructor method', options: { namedFunctionExpressions: false }, input: ` @@ -540,7 +551,10 @@ module.exports = [ { description: 'can be disabled with `transforms.classes: false`', - options: { namedFunctionExpressions: false, transforms: { classes: false } }, + options: { + namedFunctionExpressions: false, + transforms: { classes: false } + }, input: ` class Foo extends Bar { @@ -676,7 +690,8 @@ module.exports = [ }, { - description: 'verify deindent() does not corrupt string literals in class methods (#159)', + description: + 'verify deindent() does not corrupt string literals in class methods (#159)', options: { namedFunctionExpressions: false }, input: ` @@ -836,7 +851,8 @@ module.exports = [ }, { - description: 'uses correct indentation for inserted statements in constructor (#39)', + description: + 'uses correct indentation for inserted statements in constructor (#39)', options: { namedFunctionExpressions: false }, input: ` @@ -880,7 +896,8 @@ module.exports = [ }, { - description: 'uses correct indentation for inserted statements in subclass constructor (#39)', + description: + 'uses correct indentation for inserted statements in subclass constructor (#39)', options: { namedFunctionExpressions: false }, input: ` @@ -1071,7 +1088,7 @@ module.exports = [ Foo.prototype.catch = function () { // code goes here - };`, + };` }, { @@ -1149,7 +1166,8 @@ module.exports = [ }, { - description: 'static methods with computed names with varied spacing (#139)', + description: + 'static methods with computed names with varied spacing (#139)', options: { namedFunctionExpressions: false }, input: ` @@ -1201,7 +1219,8 @@ module.exports = [ }, { - description: 'static methods with numeric or string names with varied spacing (#139)', + description: + 'static methods with numeric or string names with varied spacing (#139)', options: { namedFunctionExpressions: false }, input: ` @@ -1218,7 +1237,7 @@ module.exports = [ D["Static Method"] = function (){}; D["foo"] = function (){}; ` - }, + } // TODO more tests. e.g. getters and setters. // 'super.*' is not allowed before super() diff --git a/test/samples/classes.js b/test/samples/classes.js index 4d5ff09f..31f886f1 100644 --- a/test/samples/classes.js +++ b/test/samples/classes.js @@ -40,7 +40,8 @@ module.exports = [ }, { - description: 'transpiles a class declaration without a constructor function', + description: + 'transpiles a class declaration without a constructor function', input: ` class Foo { @@ -343,7 +344,8 @@ module.exports = [ }, { - description: 'transpiles an anonymous class expression with a non-constructor method', + description: + 'transpiles an anonymous class expression with a non-constructor method', input: ` var Foo = class { @@ -656,7 +658,8 @@ module.exports = [ }, { - description: 'verify deindent() does not corrupt string literals in class methods (#159)', + description: + 'verify deindent() does not corrupt string literals in class methods (#159)', input: ` class Foo { @@ -811,7 +814,8 @@ module.exports = [ }, { - description: 'uses correct indentation for inserted statements in constructor (#39)', + description: + 'uses correct indentation for inserted statements in constructor (#39)', input: ` class Foo { @@ -854,7 +858,8 @@ module.exports = [ }, { - description: 'uses correct indentation for inserted statements in subclass constructor (#39)', + description: + 'uses correct indentation for inserted statements in subclass constructor (#39)', input: ` class Foo extends Bar { @@ -1038,7 +1043,7 @@ module.exports = [ Foo.prototype.catch = function catch$1 () { // code goes here - };`, + };` }, { @@ -1113,7 +1118,8 @@ module.exports = [ }, { - description: 'static methods with computed names with varied spacing (#139)', + description: + 'static methods with computed names with varied spacing (#139)', input: ` class B { @@ -1163,7 +1169,8 @@ module.exports = [ }, { - description: 'static methods with numeric or string names with varied spacing (#139)', + description: + 'static methods with numeric or string names with varied spacing (#139)', input: ` class D { @@ -1196,7 +1203,7 @@ module.exports = [ X.prototype.foo = function foo$1 () { return foo }; X.prototype.bar = function bar () {}; ` - }, + } // TODO more tests. e.g. getters and setters. // 'super.*' is not allowed before super() diff --git a/test/samples/computed-properties.js b/test/samples/computed-properties.js index c82a2613..575a0d52 100644 --- a/test/samples/computed-properties.js +++ b/test/samples/computed-properties.js @@ -158,7 +158,8 @@ module.exports = [ }, { - description: 'creates a computed method with a non-identifier expression (#78)', + description: + 'creates a computed method with a non-identifier expression (#78)', input: ` var obj = { @@ -175,7 +176,8 @@ module.exports = [ }, { - description: 'does not require space before parens of computed method (#82)', + description: + 'does not require space before parens of computed method (#82)', input: ` var obj = { @@ -192,7 +194,8 @@ module.exports = [ }, { - description: 'supports computed shorthand function with object spread in body (#135)', + description: + 'supports computed shorthand function with object spread in body (#135)', options: { objectAssign: 'Object.assign' @@ -215,7 +218,8 @@ module.exports = [ }, { - description: 'object literal with computed property within arrow expression (#126)', + description: + 'object literal with computed property within arrow expression (#126)', input: ` foo => bar({[x - y]: obj}); @@ -224,6 +228,5 @@ module.exports = [ !function(foo) { return bar(( obj$1 = {}, obj$1[x - y] = obj, obj$1 )) var obj$1;; }; ` - }, - + } ]; diff --git a/test/samples/destructuring.js b/test/samples/destructuring.js index 98e94af5..c2966f7a 100644 --- a/test/samples/destructuring.js +++ b/test/samples/destructuring.js @@ -87,14 +87,16 @@ module.exports = [ }, { - description: 'can be disabled in declarations with `transforms.destructuring === false`', + description: + 'can be disabled in declarations with `transforms.destructuring === false`', options: { transforms: { destructuring: false } }, input: `var { x, y } = point;`, output: `var { x, y } = point;` }, { - description: 'can be disabled in function parameters with `transforms.parameterDestructuring === false`', + description: + 'can be disabled in function parameters with `transforms.parameterDestructuring === false`', options: { transforms: { parameterDestructuring: false } }, input: `function foo ({ x, y }) {}`, output: `function foo ({ x, y }) {}` @@ -140,7 +142,8 @@ module.exports = [ }, { - description: 'does not destructure variable declarations intelligently (#53)', + description: + 'does not destructure variable declarations intelligently (#53)', input: ` var { foo: bar, baz } = obj; @@ -204,7 +207,8 @@ module.exports = [ }, { - description: 'default values in destructured object parameter with a default value (#37)', + description: + 'default values in destructured object parameter with a default value (#37)', input: ` function foo ({ arg1 = 123, arg2 = 456 } = {}) { @@ -511,7 +515,8 @@ module.exports = [ }, { - description: 'transpiles destructuring assignment of an array with a default value', + description: + 'transpiles destructuring assignment of an array with a default value', input: ` [x = 4, y] = [1, 2];`, output: ` @@ -529,7 +534,8 @@ module.exports = [ }, { - description: 'transpiles nested destructuring assignment of an array without evaluating a memberexpr twice', + description: + 'transpiles nested destructuring assignment of an array without evaluating a memberexpr twice', input: ` [[x, z], y] = [1, 2];`, output: ` @@ -538,7 +544,8 @@ module.exports = [ }, { - description: 'transpiles nested destructuring assignment of an array with a default', + description: + 'transpiles nested destructuring assignment of an array with a default', input: ` [[x] = [], y] = [1, 2];`, output: ` @@ -574,7 +581,8 @@ module.exports = [ }, { - description: 'transpiles destructuring assignment of an object where key and pattern names differ', + description: + 'transpiles destructuring assignment of an object where key and pattern names differ', input: ` ({x, y: z} = {x: 1});`, output: ` @@ -592,7 +600,8 @@ module.exports = [ }, { - description: 'transpiles destructuring assignment of an object with a default value', + description: + 'transpiles destructuring assignment of an object with a default value', input: ` ({x, y = 4} = {x: 1});`, output: ` @@ -610,7 +619,7 @@ module.exports = [ }, { - description: 'doesn\'t create an object temporary unless necessary', + description: "doesn't create an object temporary unless necessary", input: ` ({x, y: {z}} = {x: 1});`, output: ` @@ -771,5 +780,4 @@ module.exports = [ var obj; ` } - ]; diff --git a/test/samples/exponentiation-operator.js b/test/samples/exponentiation-operator.js index 6679cea1..813ca0dd 100644 --- a/test/samples/exponentiation-operator.js +++ b/test/samples/exponentiation-operator.js @@ -6,19 +6,22 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a simple reference', + description: + 'transpiles an exponentiation assignment to a simple reference', input: `x **= y`, output: `x = Math.pow( x, y )` }, { - description: 'transpiles an exponentiation assignment to a simple parenthesized reference', + description: + 'transpiles an exponentiation assignment to a simple parenthesized reference', input: `( x ) **= y`, output: `( x ) = Math.pow( x, y )` }, { - description: 'transpiles an exponentiation assignment to a rewritten simple reference', + description: + 'transpiles an exponentiation assignment to a rewritten simple reference', input: ` let x = 1; @@ -38,7 +41,8 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a simple member expression', + description: + 'transpiles an exponentiation assignment to a simple member expression', input: ` foo.bar **= y;`, @@ -48,7 +52,8 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a simple deep member expression', + description: + 'transpiles an exponentiation assignment to a simple deep member expression', input: ` foo.bar.baz **= y;`, @@ -59,7 +64,8 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a simple computed member expression', + description: + 'transpiles an exponentiation assignment to a simple computed member expression', input: ` foo[ bar ] **= y;`, @@ -69,7 +75,8 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a complex reference', + description: + 'transpiles an exponentiation assignment to a complex reference', input: ` foo[ bar() ] **= y;`, @@ -80,7 +87,8 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a contrivedly complex reference', + description: + 'transpiles an exponentiation assignment to a contrivedly complex reference', input: ` foo[ bar() ][ baz() ] **= y;`, @@ -92,7 +100,8 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a contrivedly complex reference (that is not a top-level statement)', + description: + 'transpiles an exponentiation assignment to a contrivedly complex reference (that is not a top-level statement)', input: ` var baz = 1, lolwut = foo[ bar() ][ baz * 2 ] **= y;`, @@ -103,7 +112,8 @@ module.exports = [ }, { - description: 'transpiles an exponentiation assignment to a contrivedly complex reference with simple object (that is not a top-level statement)', + description: + 'transpiles an exponentiation assignment to a contrivedly complex reference with simple object (that is not a top-level statement)', input: ` var baz = 1, lolwut = foo[ bar() ] **= y;`, @@ -153,7 +163,8 @@ module.exports = [ }, { - description: 'handles assignment of exponentiation assignment to property with side effect', + description: + 'handles assignment of exponentiation assignment to property with side effect', input: ` x=a[bar()]**=2; @@ -162,7 +173,7 @@ module.exports = [ var property; x=( property = bar(), a[property]=Math.pow( a[property], 2 ) ); ` - }, + } /* TODO: Test currently errors out with: TypeError: Cannot read property 'property' of null { diff --git a/test/samples/for-of.js b/test/samples/for-of.js index 6bf4bf2c..ec9b643b 100644 --- a/test/samples/for-of.js +++ b/test/samples/for-of.js @@ -13,7 +13,8 @@ module.exports = [ }, { - description: 'transpiles for-of with array assumption with `transforms.dangerousForOf`', + description: + 'transpiles for-of with array assumption with `transforms.dangerousForOf`', options: { transforms: { dangerousForOf: true } }, input: ` @@ -118,7 +119,6 @@ module.exports = [ if ( item.foo ) { continue; } }` - }, { diff --git a/test/samples/generators.js b/test/samples/generators.js index b0a90c32..b58149ca 100644 --- a/test/samples/generators.js +++ b/test/samples/generators.js @@ -48,28 +48,32 @@ module.exports = [ }, { - description: 'ignores generator function declarations with `transforms.generator: false`', + description: + 'ignores generator function declarations with `transforms.generator: false`', options: { transforms: { generator: false } }, input: `function* foo () {}`, output: `function* foo () {}` }, { - description: 'ignores generator function expressions with `transforms.generator: false`', + description: + 'ignores generator function expressions with `transforms.generator: false`', options: { transforms: { generator: false } }, input: `var foo = function* foo () {}`, output: `var foo = function* foo () {}` }, { - description: 'ignores generator function methods with `transforms.generator: false`', + description: + 'ignores generator function methods with `transforms.generator: false`', options: { transforms: { generator: false } }, input: `var obj = { *foo () {} }`, output: `var obj = { foo: function* foo () {} }` }, { - description: 'ignores generator function class methods with `transforms.generator: false`', + description: + 'ignores generator function class methods with `transforms.generator: false`', options: { transforms: { generator: false } }, input: ` class Foo { diff --git a/test/samples/jsx.js b/test/samples/jsx.js index fe1b2fad..745ca810 100644 --- a/test/samples/jsx.js +++ b/test/samples/jsx.js @@ -136,7 +136,7 @@ module.exports = [ input: `

Hello {name} - !${" "} + !${' '} It's nice to meet you

`, output: ` @@ -177,7 +177,8 @@ module.exports = [ }, { - description: 'transpiles mixed JSX spread attributes ending in spread with custom Object.assign', + description: + 'transpiles mixed JSX spread attributes ending in spread with custom Object.assign', options: { objectAssign: 'angular.extend' }, @@ -186,7 +187,8 @@ module.exports = [ }, { - description: 'transpiles mixed JSX spread attributes ending in other values', + description: + 'transpiles mixed JSX spread attributes ending in other values', options: { objectAssign: 'Object.assign' }, diff --git a/test/samples/loops.js b/test/samples/loops.js index dcc8aef0..7f969450 100644 --- a/test/samples/loops.js +++ b/test/samples/loops.js @@ -30,7 +30,8 @@ module.exports = [ }, { - description: 'transpiles block scoping inside while loops with function bodies', + description: + 'transpiles block scoping inside while loops with function bodies', input: ` function log ( square ) { @@ -60,7 +61,8 @@ module.exports = [ }, { - description: 'transpiles block scoping inside do-while loops with function bodies', + description: + 'transpiles block scoping inside do-while loops with function bodies', input: ` function log ( square ) { @@ -92,7 +94,8 @@ module.exports = [ }, { - description: 'transpiles block-less for loops with block-scoped declarations inside function body', + description: + 'transpiles block-less for loops with block-scoped declarations inside function body', input: ` for ( let i = 0; i < 10; i += 1 ) setTimeout( () => console.log( i ), i * 100 );`, @@ -106,7 +109,8 @@ module.exports = [ }, { - description: 'transpiles block scoping inside loops without function bodies', + description: + 'transpiles block scoping inside loops without function bodies', input: ` for ( let i = 0; i < 10; i += 1 ) { @@ -122,7 +126,8 @@ module.exports = [ }, { - description: 'transpiles block-less for loops without block-scoped declarations inside function body', + description: + 'transpiles block-less for loops without block-scoped declarations inside function body', input: ` for ( let i = 0; i < 10; i += 1 ) console.log( i );`, @@ -132,7 +137,8 @@ module.exports = [ }, { - description: 'preserves correct `this` and `arguments` inside block scoped loop (#10)', + description: + 'preserves correct `this` and `arguments` inside block scoped loop (#10)', input: ` for ( let i = 0; i < 10; i += 1 ) { @@ -157,7 +163,8 @@ module.exports = [ }, { - description: 'maintains value of for loop variables between iterations (#11)', + description: + 'maintains value of for loop variables between iterations (#11)', input: ` var fns = []; @@ -181,7 +188,8 @@ module.exports = [ }, { - description: 'maintains value of for loop variables between iterations, with conflict (#11)', + description: + 'maintains value of for loop variables between iterations, with conflict (#11)', input: ` var i = 'conflicting'; @@ -207,7 +215,8 @@ module.exports = [ }, { - description: 'loop variables with UpdateExpresssions between iterations (#150)', + description: + 'loop variables with UpdateExpresssions between iterations (#150)', input: ` var fns = []; @@ -234,7 +243,8 @@ module.exports = [ }, { - description: 'loop variables with UpdateExpresssions between iterations, with conflict (#150)', + description: + 'loop variables with UpdateExpresssions between iterations, with conflict (#150)', input: ` var i = 'conflicting'; @@ -349,7 +359,8 @@ module.exports = [ }, { - description: 'does not incorrectly rename variables declared in for loop head', + description: + 'does not incorrectly rename variables declared in for loop head', input: ` for ( let foo = 0; foo < 10; foo += 1 ) { @@ -365,7 +376,8 @@ module.exports = [ }, { - description: 'does not rewrite as function if `transforms.letConst === false`', + description: + 'does not rewrite as function if `transforms.letConst === false`', options: { transforms: { letConst: false } }, input: ` @@ -514,7 +526,8 @@ module.exports = [ }, { - description: 'complex destructuring in variable declaration in for loop head', + description: + 'complex destructuring in variable declaration in for loop head', input: ` var range = function () { @@ -536,7 +549,8 @@ module.exports = [ }, { - description: 'arrow functions in block-less for loops in a block-less if/else chain (#110)', + description: + 'arrow functions in block-less for loops in a block-less if/else chain (#110)', input: ` if (x) @@ -595,7 +609,8 @@ module.exports = [ }, { - description: 'always initialises block-scoped variable in for-of loop (#125)', + description: + 'always initialises block-scoped variable in for-of loop (#125)', options: { transforms: { dangerousForOf: true } }, @@ -618,11 +633,12 @@ module.exports = [ f(b, j, k, x, y) } } - `, + ` }, { - description: 'always initialises block-scoped variable in simple for-of loop (#125)', + description: + 'always initialises block-scoped variable in simple for-of loop (#125)', options: { transforms: { dangerousForOf: true } }, @@ -639,7 +655,7 @@ module.exports = [ var x = (void 0), y = 2, z = (void 0); f(b, x++, y++, z++) } - `, + ` }, { @@ -658,11 +674,12 @@ module.exports = [ var x = (void 0), y = 2, z = (void 0); f(k, r++, s++, t++, x++, y++, z++) } - `, + ` }, { - description: 'use alias for this in right side of nested for-in loop declaration (#142)', + description: + 'use alias for this in right side of nested for-in loop declaration (#142)', input: ` let arr = []; @@ -701,11 +718,12 @@ module.exports = [ console.log( arr.join( ' ' ) ); }; new Foo().do(); - `, + ` }, { - description: 'use alias for this in right side of nested for-of loop declaration (#142)', + description: + 'use alias for this in right side of nested for-of loop declaration (#142)', options: { transforms: { dangerousForOf: true } }, @@ -750,7 +768,6 @@ module.exports = [ console.log( arr.join( ' ' ) ); }; new Foo().do(); - `, - }, - + ` + } ]; diff --git a/test/samples/misc.js b/test/samples/misc.js index 84507adb..5900ffd7 100644 --- a/test/samples/misc.js +++ b/test/samples/misc.js @@ -96,7 +96,8 @@ module.exports = [ }, { - description: 'Safari/WebKit bug workaround: parameter shadowing function expression name (#154)', + description: + 'Safari/WebKit bug workaround: parameter shadowing function expression name (#154)', input: ` "use strict"; // necessary to trigger WebKit bug @@ -184,6 +185,5 @@ module.exports = [ return bar; } ` - }, - + } ]; diff --git a/test/samples/modules.js b/test/samples/modules.js index 6e443cb2..772fc450 100644 --- a/test/samples/modules.js +++ b/test/samples/modules.js @@ -26,7 +26,8 @@ module.exports = [ }, { - description: 'imports and exports are ignored with `transforms.modules === false`', + description: + 'imports and exports are ignored with `transforms.modules === false`', options: { transforms: { modules: false } }, input: `import 'foo'; export { foo };`, output: `import 'foo'; export { foo };` diff --git a/test/samples/object-properties-no-named-function-expressions.js b/test/samples/object-properties-no-named-function-expressions.js index d3a99102..76109eb6 100644 --- a/test/samples/object-properties-no-named-function-expressions.js +++ b/test/samples/object-properties-no-named-function-expressions.js @@ -52,7 +52,8 @@ module.exports = [ }, { - description: 'transpiles shorthand methods with numeric or string names (#139)', + description: + 'transpiles shorthand methods with numeric or string names (#139)', options: { namedFunctionExpressions: false }, input: ` @@ -83,15 +84,23 @@ module.exports = [ }, { - description: 'shorthand properties can be disabled with `transforms.conciseMethodProperty === false`', - options: { namedFunctionExpressions: false, transforms: { conciseMethodProperty: false } }, + description: + 'shorthand properties can be disabled with `transforms.conciseMethodProperty === false`', + options: { + namedFunctionExpressions: false, + transforms: { conciseMethodProperty: false } + }, input: `var obj = { x, y, z () {} }`, output: `var obj = { x, y, z () {} }` }, { - description: 'computed properties can be disabled with `transforms.computedProperty === false`', - options: { namedFunctionExpressions: false, transforms: { computedProperty: false } }, + description: + 'computed properties can be disabled with `transforms.computedProperty === false`', + options: { + namedFunctionExpressions: false, + transforms: { computedProperty: false } + }, input: `var obj = { [x]: 'x' }`, output: `var obj = { [x]: 'x' }` }, @@ -114,5 +123,5 @@ module.exports = [ { console.log(JSON.stringify(( obj$1 = {}, obj$1['bar'] = 3, obj$1 ))); var obj$1; } ` - }, + } ]; diff --git a/test/samples/object-properties.js b/test/samples/object-properties.js index 4f28c9ec..46711d41 100644 --- a/test/samples/object-properties.js +++ b/test/samples/object-properties.js @@ -48,7 +48,8 @@ module.exports = [ }, { - description: 'transpiles shorthand methods with numeric or string names (#139)', + description: + 'transpiles shorthand methods with numeric or string names (#139)', input: ` obj = { @@ -78,14 +79,16 @@ module.exports = [ }, { - description: 'shorthand properties can be disabled with `transforms.conciseMethodProperty === false`', + description: + 'shorthand properties can be disabled with `transforms.conciseMethodProperty === false`', options: { transforms: { conciseMethodProperty: false } }, input: `var obj = { x, y, z () {} }`, output: `var obj = { x, y, z () {} }` }, { - description: 'computed properties can be disabled with `transforms.computedProperty === false`', + description: + 'computed properties can be disabled with `transforms.computedProperty === false`', options: { transforms: { computedProperty: false } }, input: `var obj = { [x]: 'x' }`, output: `var obj = { [x]: 'x' }` @@ -125,5 +128,5 @@ module.exports = [ bar: function bar() {} } ` - }, + } ]; diff --git a/test/samples/object-rest-spread.js b/test/samples/object-rest-spread.js index a2769471..8223da20 100644 --- a/test/samples/object-rest-spread.js +++ b/test/samples/object-rest-spread.js @@ -98,7 +98,8 @@ module.exports = [ }, { - description: 'transpiles inline objects with spread with computed property (#144)', + description: + 'transpiles inline objects with spread with computed property (#144)', options: { objectAssign: 'Object.assign' }, diff --git a/test/samples/spread-operator.js b/test/samples/spread-operator.js index fe78410d..d831eeab 100644 --- a/test/samples/spread-operator.js +++ b/test/samples/spread-operator.js @@ -24,13 +24,15 @@ module.exports = [ }, { - description: 'transpiles a spread operator in a method call with other arguments', + description: + 'transpiles a spread operator in a method call with other arguments', input: `var max = Math.max( 0, ...values );`, output: `var max = Math.max.apply( Math, [ 0 ].concat( values ) );` }, { - description: 'transpiles a spread operator in a method call of an expression', + description: + 'transpiles a spread operator in a method call of an expression', input: ` ( foo || bar ).baz( ...values );`, @@ -55,7 +57,8 @@ module.exports = [ }, { - description: 'transpiles a spread operator in a call in an arrow function using this (#115)', + description: + 'transpiles a spread operator in a call in an arrow function using this (#115)', input: ` function foo(...args) { @@ -106,7 +109,8 @@ module.exports = [ }, { - description: 'transpiles a spread operator in a new call in an arrow function using this', + description: + 'transpiles a spread operator in a new call in an arrow function using this', input: ` function foo(...args) { @@ -156,7 +160,8 @@ module.exports = [ }, { - description: 'transpiles a spread operator in an expression method call within an if', + description: + 'transpiles a spread operator in an expression method call within an if', input: ` var result; @@ -173,7 +178,8 @@ module.exports = [ }, { - description: 'transpiles spread operators in expression method calls within a function', + description: + 'transpiles spread operators in expression method calls within a function', input: ` function foo() { @@ -245,9 +251,11 @@ module.exports = [ }, { - description: 'transpiles spread operators with template literals (issue #99)', + description: + 'transpiles spread operators with template literals (issue #99)', input: 'console.log( `%s ${label}:`, `${color}`, ...args );', - output: 'console.log.apply( console, [ ("%s " + label + ":"), ("" + color) ].concat( args ) );' + output: + 'console.log.apply( console, [ ("%s " + label + ":"), ("" + color) ].concat( args ) );' }, { @@ -257,7 +265,8 @@ module.exports = [ }, { - description: 'transpiles a spread operator in a function call with other arguments', + description: + 'transpiles a spread operator in a function call with other arguments', input: `sprintf( str, ...values );`, output: `sprintf.apply( void 0, [ str ].concat( values ) );` }, @@ -269,14 +278,16 @@ module.exports = [ }, { - description: 'can be disabled in array expressions `transforms.spreadRest: false`', + description: + 'can be disabled in array expressions `transforms.spreadRest: false`', options: { transforms: { spreadRest: false } }, input: `var chars = [ ...string ]`, output: `var chars = [ ...string ]` }, { - description: 'can be disabled in call expressions with `transforms.spreadRest: false`', + description: + 'can be disabled in call expressions with `transforms.spreadRest: false`', options: { transforms: { spreadRest: false } }, input: `var max = Math.max( ...values );`, output: `var max = Math.max( ...values );` @@ -289,7 +300,8 @@ module.exports = [ }, { - description: 'transpiles multiple spread operators in an array with trailing comma', + description: + 'transpiles multiple spread operators in an array with trailing comma', input: `var arr = [ ...a, ...b, ...c, ];`, output: `var arr = a.concat( b, c );` }, @@ -301,7 +313,8 @@ module.exports = [ }, { - description: 'transpiles mixture of spread and non-spread elements in array with trailing comma', + description: + 'transpiles mixture of spread and non-spread elements in array with trailing comma', input: `var arr = [ ...a, b, ...c, d, ];`, output: `var arr = a.concat( [b], c, [d] );` }, @@ -370,7 +383,8 @@ module.exports = [ }, { - description: 'transpiles mixture of spread and non-spread operators in function call', + description: + 'transpiles mixture of spread and non-spread operators in function call', input: `var max = Math.max( ...a, b, ...c, d );`, output: `var max = Math.max.apply( Math, a.concat( [b], c, [d] ) );` }, @@ -559,6 +573,5 @@ module.exports = [ var ref$1;; }; } } ` - }, - + } ]; diff --git a/test/samples/template-strings.js b/test/samples/template-strings.js index 19eaa5cd..6b69b506 100644 --- a/test/samples/template-strings.js +++ b/test/samples/template-strings.js @@ -12,7 +12,8 @@ module.exports = [ }, { - description: 'transpiles an untagged template literal containing complex expressions', + description: + 'transpiles an untagged template literal containing complex expressions', input: 'var str = `foo${bar + baz}qux`;', output: `var str = "foo" + (bar + baz) + "qux";` }, @@ -36,14 +37,16 @@ module.exports = [ }, { - description: 'transpiles tagged template literals with `transforms.dangerousTaggedTemplateString = true`', + description: + 'transpiles tagged template literals with `transforms.dangerousTaggedTemplateString = true`', options: { transforms: { dangerousTaggedTemplateString: true } }, input: 'var str = x`y${(() => 42)()}`;', output: `var str = x(["y", ""], (function () { return 42; })());` }, { - description: 'transpiles tagged template literals with `transforms.dangerousTaggedTemplateString = true`', + description: + 'transpiles tagged template literals with `transforms.dangerousTaggedTemplateString = true`', options: { transforms: { dangerousTaggedTemplateString: true } }, input: 'var str = x`${(() => 42)()}y`;', output: `var str = x(["", "y"], (function () { return 42; })());` @@ -62,7 +65,8 @@ module.exports = [ }, { - description: 'does not parenthesise template strings in arithmetic expressions', + description: + 'does not parenthesise template strings in arithmetic expressions', input: 'var str = `x${y}` + z; var str2 = `x${y}` * z;', output: 'var str = "x" + y + z; var str2 = ("x" + y) * z;' }, diff --git a/test/test.js b/test/test.js index db70966b..0c91a14e 100644 --- a/test/test.js +++ b/test/test.js @@ -1,238 +1,266 @@ -var path = require( 'path' ); -var fs = require( 'fs' ); -var rimraf = require( 'rimraf' ); -var child_process = require( 'child_process' ); -var assert = require( 'assert' ); -var glob = require( 'glob' ); -var SourceMapConsumer = require( 'source-map' ).SourceMapConsumer; -var getLocation = require( './utils/getLocation.js' ); -var buble = require( '../dist/buble.umd.js' ); - -require( 'source-map-support' ).install(); -require( 'console-group' ).install(); - -function equal ( a, b ) { - assert.equal( showInvisibles( a ), showInvisibles( b ) ); +var path = require('path'); +var fs = require('fs'); +var rimraf = require('rimraf'); +var child_process = require('child_process'); +var assert = require('assert'); +var glob = require('glob'); +var SourceMapConsumer = require('source-map').SourceMapConsumer; +var getLocation = require('./utils/getLocation.js'); +var buble = require('../dist/buble.umd.js'); + +require('source-map-support').install(); +require('console-group').install(); + +function equal(a, b) { + assert.equal(showInvisibles(a), showInvisibles(b)); } -function showInvisibles ( str ) { +function showInvisibles(str) { return str - .replace( /^ +/gm, spaces => repeat( '•', spaces.length ) ) - .replace( / +$/gm, spaces => repeat( '•', spaces.length ) ) - .replace( /^\t+/gm, tabs => repeat( '› ', tabs.length ) ) - .replace( /\t+$/gm, tabs => repeat( '› ', tabs.length ) ); + .replace(/^ +/gm, spaces => repeat('•', spaces.length)) + .replace(/ +$/gm, spaces => repeat('•', spaces.length)) + .replace(/^\t+/gm, tabs => repeat('› ', tabs.length)) + .replace(/\t+$/gm, tabs => repeat('› ', tabs.length)); } -function repeat ( str, times ) { +function repeat(str, times) { var result = ''; - while ( times-- ) result += str; + while (times--) result += str; return result; } -const subsetIndex = process.argv.indexOf( '--subset' ); -const subset = ~subsetIndex ? process.argv[ subsetIndex + 1 ].split( ',' ).map( file => `${file}.js` ) : null; -const subsetFilter = subset ? file => ~subset.indexOf( file ) : () => true; - -describe( 'buble', () => { - fs.readdirSync( 'test/samples' ).filter( subsetFilter ).forEach( file => { - if ( !/\.js$/.test( file ) ) return; // avoid vim .js.swp files - var samples = require( './samples/' + file ); - - describe( path.basename( file ), () => { - samples.forEach( sample => { - ( sample.solo ? it.only : sample.skip ? it.skip : it )( sample.description, () => { - if ( sample.error ) { - assert.throws( () => { - buble.transform( sample.input, sample.options ); - }, sample.error ); - } - - else { - equal( buble.transform( sample.input, sample.options ).code, sample.output ); - } +const subsetIndex = process.argv.indexOf('--subset'); +const subset = ~subsetIndex + ? process.argv[subsetIndex + 1].split(',').map(file => `${file}.js`) + : null; +const subsetFilter = subset ? file => ~subset.indexOf(file) : () => true; + +describe('buble', () => { + fs + .readdirSync('test/samples') + .filter(subsetFilter) + .forEach(file => { + if (!/\.js$/.test(file)) return; // avoid vim .js.swp files + var samples = require('./samples/' + file); + + describe(path.basename(file), () => { + samples.forEach(sample => { + (sample.solo ? it.only : sample.skip ? it.skip : it)( + sample.description, + () => { + if (sample.error) { + assert.throws(() => { + buble.transform(sample.input, sample.options); + }, sample.error); + } else { + equal( + buble.transform(sample.input, sample.options).code, + sample.output + ); + } + } + ); }); }); }); - }); - if ( subset ) return; + if (subset) return; - describe( 'cli', () => { - fs.readdirSync( 'test/cli' ).forEach( dir => { - if ( dir[0] === '.' ) return; // .DS_Store + describe('cli', () => { + fs.readdirSync('test/cli').forEach(dir => { + if (dir[0] === '.') return; // .DS_Store - it( dir, done => { - dir = path.resolve( 'test/cli', dir ); - rimraf.sync( path.resolve( dir, 'actual' ) ); - fs.mkdirSync( path.resolve( dir, 'actual' ) ); + it(dir, done => { + dir = path.resolve('test/cli', dir); + rimraf.sync(path.resolve(dir, 'actual')); + fs.mkdirSync(path.resolve(dir, 'actual')); var binFile = path.resolve(__dirname, '../bin/buble'); - var commandFile = path.resolve( dir, 'command.sh' ); - - var command = fs.readFileSync( commandFile, 'utf-8' ) - .replace( 'buble', 'node "' + binFile + '"' ); - child_process.exec( command, { - cwd: dir - }, ( err, stdout, stderr ) => { - if ( err ) return done( err ); - - if ( stdout ) console.log( stdout ); - if ( stderr ) console.error( stderr ); - - function catalogue ( subdir ) { - subdir = path.resolve( dir, subdir ); - - return glob.sync( '**/*.js?(.map)', { cwd: subdir }) - .sort() - .map( name => { - var contents = fs.readFileSync( path.resolve( subdir, name ), 'utf-8' ) - .replace(/\r\n/g, '\n') - .trim(); - - if ( path.extname( name ) === '.map' ) { - contents = JSON.parse( contents ); - } - - return { name, contents }; - }); + var commandFile = path.resolve(dir, 'command.sh'); + + var command = fs + .readFileSync(commandFile, 'utf-8') + .replace('buble', 'node "' + binFile + '"'); + child_process.exec( + command, + { + cwd: dir + }, + (err, stdout, stderr) => { + if (err) return done(err); + + if (stdout) console.log(stdout); + if (stderr) console.error(stderr); + + function catalogue(subdir) { + subdir = path.resolve(dir, subdir); + + return glob + .sync('**/*.js?(.map)', { cwd: subdir }) + .sort() + .map(name => { + var contents = fs + .readFileSync(path.resolve(subdir, name), 'utf-8') + .replace(/\r\n/g, '\n') + .trim(); + + if (path.extname(name) === '.map') { + contents = JSON.parse(contents); + } + + return { name, contents }; + }); + } + + var expected = catalogue('expected'); + var actual = catalogue('actual'); + + try { + assert.deepEqual(actual, expected); + done(); + } catch (err) { + done(err); + } } - - var expected = catalogue( 'expected' ); - var actual = catalogue( 'actual' ); - - try { - assert.deepEqual( actual, expected ); - done(); - } catch ( err ) { - done( err ); - } - }); + ); }); }); }); - describe( 'errors', () => { - it( 'reports the location of a syntax error', () => { + describe('errors', () => { + it('reports the location of a syntax error', () => { var source = `var 42 = nope;`; try { - buble.transform( source ); - } catch ( err ) { - assert.equal( err.name, 'SyntaxError' ); - assert.deepEqual( err.loc, { line: 1, column: 4 }); - assert.equal( err.message, 'Unexpected token (1:4)' ); - assert.equal( err.snippet, `1 : var 42 = nope;\n ^` ); - assert.equal( err.toString(), `SyntaxError: Unexpected token (1:4)\n1 : var 42 = nope;\n ^` ); + buble.transform(source); + } catch (err) { + assert.equal(err.name, 'SyntaxError'); + assert.deepEqual(err.loc, { line: 1, column: 4 }); + assert.equal(err.message, 'Unexpected token (1:4)'); + assert.equal(err.snippet, `1 : var 42 = nope;\n ^`); + assert.equal( + err.toString(), + `SyntaxError: Unexpected token (1:4)\n1 : var 42 = nope;\n ^` + ); } }); - it( 'reports the location of a compile error', () => { + it('reports the location of a compile error', () => { var source = `const x = 1; x++;`; try { - buble.transform( source ); - } catch ( err ) { - assert.equal( err.name, 'CompileError' ); - assert.equal( err.loc.line, 1 ); - assert.equal( err.loc.column, 13 ); - assert.equal( err.message, 'x is read-only (1:13)' ); - assert.equal( err.snippet, `1 : const x = 1; x++;\n ^^^` ); - assert.equal( err.toString(), `CompileError: x is read-only (1:13)\n1 : const x = 1; x++;\n ^^^` ); + buble.transform(source); + } catch (err) { + assert.equal(err.name, 'CompileError'); + assert.equal(err.loc.line, 1); + assert.equal(err.loc.column, 13); + assert.equal(err.message, 'x is read-only (1:13)'); + assert.equal( + err.snippet, + `1 : const x = 1; x++;\n ^^^` + ); + assert.equal( + err.toString(), + `CompileError: x is read-only (1:13)\n1 : const x = 1; x++;\n ^^^` + ); } }); }); - describe( 'target', () => { - it( 'determines necessary transforms for a target environment', () => { + describe('target', () => { + it('determines necessary transforms for a target environment', () => { var transforms = buble.target({ chrome: 49 }); - assert.ok( transforms.moduleImport ); - assert.ok( !transforms.arrow ); + assert.ok(transforms.moduleImport); + assert.ok(!transforms.arrow); }); - it( 'returns lowest common denominator support info', () => { + it('returns lowest common denominator support info', () => { var transforms = buble.target({ chrome: 49, node: 5 }); - assert.ok( transforms.defaultParameter ); - assert.ok( !transforms.arrow ); + assert.ok(transforms.defaultParameter); + assert.ok(!transforms.arrow); }); - it( 'only applies necessary transforms', () => { + it('only applies necessary transforms', () => { var source = ` const power = ( base, exponent = 2 ) => Math.pow( base, exponent );`; - var result = buble.transform( source, { + var result = buble.transform(source, { target: { chrome: 49, node: 5 } }).code; - assert.equal( result, ` + assert.equal( + result, + ` const power = ( base, exponent ) => { if ( exponent === void 0 ) exponent = 2; return Math.pow( base, exponent ); - };` ); + };` + ); }); }); - describe( 'sourcemaps', () => { - it( 'generates a valid sourcemap', () => { - var map = buble.transform( '' ).map; - assert.equal( map.version, 3 ); + describe('sourcemaps', () => { + it('generates a valid sourcemap', () => { + var map = buble.transform('').map; + assert.equal(map.version, 3); }); - it( 'uses provided file and source', () => { - var map = buble.transform( '', { + it('uses provided file and source', () => { + var map = buble.transform('', { file: 'output.js', source: 'input.js' }).map; - assert.equal( map.file, 'output.js' ); - assert.deepEqual( map.sources, [ 'input.js' ] ); + assert.equal(map.file, 'output.js'); + assert.deepEqual(map.sources, ['input.js']); }); - it( 'includes content by default', () => { + it('includes content by default', () => { var source = `let { x, y } = foo();`; - var map = buble.transform( source ).map; + var map = buble.transform(source).map; - assert.deepEqual( map.sourcesContent, [ source ] ); + assert.deepEqual(map.sourcesContent, [source]); }); - it( 'excludes content if requested', () => { + it('excludes content if requested', () => { var source = `let { x, y } = foo();`; - var map = buble.transform( source, { + var map = buble.transform(source, { includeContent: false }).map; - assert.deepEqual( map.sourcesContent, [ null ] ); + assert.deepEqual(map.sourcesContent, [null]); }); - it( 'locates original content', () => { + it('locates original content', () => { var source = `const add = ( a, b ) => a + b;`; - var result = buble.transform( source, { + var result = buble.transform(source, { file: 'output.js', source: 'input.js' }); - var smc = new SourceMapConsumer( result.map ); + var smc = new SourceMapConsumer(result.map); - var location = getLocation( result.code, 'add' ); - var expected = getLocation( source, 'add' ); + var location = getLocation(result.code, 'add'); + var expected = getLocation(source, 'add'); - var actual = smc.originalPositionFor( location ); + var actual = smc.originalPositionFor(location); - assert.deepEqual( actual, { + assert.deepEqual(actual, { line: expected.line, column: expected.column, source: 'input.js', name: null }); - location = getLocation( result.code, 'a +' ); - expected = getLocation( source, 'a +' ); + location = getLocation(result.code, 'a +'); + expected = getLocation(source, 'a +'); - actual = smc.originalPositionFor( location ); + actual = smc.originalPositionFor(location); - assert.deepEqual( actual, { + assert.deepEqual(actual, { line: expected.line, column: expected.column, source: 'input.js', @@ -240,36 +268,36 @@ describe( 'buble', () => { }); }); - it( 'recovers names', () => { + it('recovers names', () => { var source = ` const foo = 1; if ( x ) { const foo = 2; }`; - var result = buble.transform( source, { + var result = buble.transform(source, { file: 'output.js', source: 'input.js' }); - var smc = new SourceMapConsumer( result.map ); + var smc = new SourceMapConsumer(result.map); - var location = getLocation( result.code, 'var' ); - var actual = smc.originalPositionFor( location ); + var location = getLocation(result.code, 'var'); + var actual = smc.originalPositionFor(location); - assert.equal( actual.name, 'const' ); + assert.equal(actual.name, 'const'); - location = getLocation( result.code, 'var', location.char + 1 ); - actual = smc.originalPositionFor( location ); + location = getLocation(result.code, 'var', location.char + 1); + actual = smc.originalPositionFor(location); - assert.equal( actual.name, 'const' ); + assert.equal(actual.name, 'const'); - location = getLocation( result.code, 'foo$1', location.char + 1 ); - actual = smc.originalPositionFor( location ); + location = getLocation(result.code, 'foo$1', location.char + 1); + actual = smc.originalPositionFor(location); - assert.equal( actual.name, 'foo' ); + assert.equal(actual.name, 'foo'); }); - it( 'handles moved content', () => { + it('handles moved content', () => { var source = ` for ( let i = 0; i < 10; i += 1 ) { const square = i * i; @@ -278,30 +306,30 @@ describe( 'buble', () => { }, i * 100 ); }`; - var result = buble.transform( source, { + var result = buble.transform(source, { file: 'output.js', source: 'input.js' }); - var smc = new SourceMapConsumer( result.map ); + var smc = new SourceMapConsumer(result.map); - var location = getLocation( result.code, 'i < 10' ); - var expected = getLocation( source, 'i < 10' ); + var location = getLocation(result.code, 'i < 10'); + var expected = getLocation(source, 'i < 10'); - var actual = smc.originalPositionFor( location ); + var actual = smc.originalPositionFor(location); - assert.deepEqual( actual, { + assert.deepEqual(actual, { line: expected.line, column: expected.column, source: 'input.js', name: null }); - location = getLocation( result.code, 'setTimeout' ); - expected = getLocation( source, 'setTimeout' ); + location = getLocation(result.code, 'setTimeout'); + expected = getLocation(source, 'setTimeout'); - actual = smc.originalPositionFor( location ); + actual = smc.originalPositionFor(location); - assert.deepEqual( actual, { + assert.deepEqual(actual, { line: expected.line, column: expected.column, source: 'input.js', diff --git a/test/utils/getLocation.js b/test/utils/getLocation.js index 78742ccd..bbf6f890 100644 --- a/test/utils/getLocation.js +++ b/test/utils/getLocation.js @@ -1,24 +1,24 @@ -module.exports = function getLocation ( source, search, start ) { - if ( typeof search === 'string' ) { - search = source.indexOf( search, start ); +module.exports = function getLocation(source, search, start) { + if (typeof search === 'string') { + search = source.indexOf(search, start); } - var lines = source.split( '\n' ); + var lines = source.split('\n'); var len = lines.length; var lineStart = 0; var i; - 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 > search ) { + if (lineEnd > search) { return { line: i + 1, column: search - lineStart, char: i }; } lineStart = lineEnd; } - throw new Error( 'Could not determine location of character' ); -} + throw new Error('Could not determine location of character'); +};