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 =