From 1b36c09e5025da90edeb54c5bdcc2d9095684930 Mon Sep 17 00:00:00 2001
From: Rich Harris <richard.a.harris@gmail.com>
Date: Thu, 21 May 2015 15:53:09 -0400
Subject: [PATCH] remove _private props from Statement

---
 src/Bundle.js      | 24 ++++++++++++------------
 src/Module.js      | 21 +++++++++++----------
 src/Statement.js   | 14 +++++++++++++-
 src/ast/analyse.js | 34 +++++++++++-----------------------
 4 files changed, 47 insertions(+), 46 deletions(-)

diff --git a/src/Bundle.js b/src/Bundle.js
index 604fe80..fd8b003 100644
--- a/src/Bundle.js
+++ b/src/Bundle.js
@@ -89,7 +89,7 @@ export default class Bundle {
 
 		// Discover conflicts (i.e. two statements in separate modules both define `foo`)
 		this.statements.forEach( statement => {
-			keys( statement._defines ).forEach( name => {
+			keys( statement.defines ).forEach( name => {
 				if ( has( definers, name ) ) {
 					conflicts[ name ] = true;
 				} else {
@@ -98,7 +98,7 @@ export default class Bundle {
 
 				// TODO in good js, there shouldn't be duplicate definitions
 				// per module... but some people write bad js
-				definers[ name ].push( statement._module );
+				definers[ name ].push( statement.module );
 			});
 		});
 
@@ -151,17 +151,17 @@ export default class Bundle {
 		this.statements.forEach( statement => {
 			let replacements = {};
 
-			keys( statement._dependsOn )
-				.concat( keys( statement._defines ) )
+			keys( statement.dependsOn )
+				.concat( keys( statement.defines ) )
 				.forEach( name => {
-					const canonicalName = statement._module.getCanonicalName( name );
+					const canonicalName = statement.module.getCanonicalName( name );
 
 					if ( name !== canonicalName ) {
 						replacements[ name ] = canonicalName;
 					}
 				});
 
-			const source = statement._source.clone().trim();
+			const source = statement.source.clone().trim();
 
 			// modify exports as necessary
 			if ( /^Export/.test( statement.node.type ) ) {
@@ -182,7 +182,7 @@ export default class Bundle {
 				}
 
 				else if ( statement.node.type === 'ExportDefaultDeclaration' ) {
-					const module = statement._module;
+					const module = statement.module;
 					const canonicalName = module.getCanonicalName( 'default' );
 
 					if ( statement.node.declaration.type === 'Identifier' && canonicalName === module.getCanonicalName( statement.node.declaration.name ) ) {
@@ -200,8 +200,8 @@ export default class Bundle {
 			replaceIdentifiers( statement.node, source, replacements );
 
 			// add leading comments
-			if ( statement._leadingComments.length ) {
-				const commentBlock = statement._leadingComments.map( comment => {
+			if ( statement.leadingComments.length ) {
+				const commentBlock = statement.leadingComments.map( comment => {
 					return comment.block ?
 						`/*${comment.text}*/` :
 						`//${comment.text}`;
@@ -211,7 +211,7 @@ export default class Bundle {
 			}
 
 			// add margin
-			const margin = Math.max( statement._margin[0], previousMargin );
+			const margin = Math.max( statement.margin[0], previousMargin );
 			const newLines = new Array( margin ).join( '\n' );
 
 			// add the statement itself
@@ -221,7 +221,7 @@ export default class Bundle {
 			});
 
 			// add trailing comments
-			const comment = statement._trailingComment;
+			const comment = statement.trailingComment;
 			if ( comment ) {
 				const commentBlock = comment.block ?
 					` /*${comment.text}*/` :
@@ -230,7 +230,7 @@ export default class Bundle {
 				magicString.append( commentBlock );
 			}
 
-			previousMargin = statement._margin[1];
+			previousMargin = statement.margin[1];
 		});
 
 		// prepend bundle with internal namespaces
diff --git a/src/Module.js b/src/Module.js
index 4be3d08..689e5ad 100644
--- a/src/Module.js
+++ b/src/Module.js
@@ -36,7 +36,8 @@ export default class Module {
 		}
 
 		this.statements = this.ast.body.map( node => {
-			return new Statement( node );
+			const source = this.code.snip( node.start, node.end );
+			return new Statement( node, source, this );
 		});
 
 		this.analyse();
@@ -159,11 +160,11 @@ export default class Module {
 		this.modifications = {};
 
 		this.statements.forEach( statement => {
-			Object.keys( statement._defines ).forEach( name => {
+			Object.keys( statement.defines ).forEach( name => {
 				this.definitions[ name ] = statement;
 			});
 
-			Object.keys( statement._modifies ).forEach( name => {
+			Object.keys( statement.modifies ).forEach( name => {
 				if ( !has( this.modifications, name ) ) {
 					this.modifications[ name ] = [];
 				}
@@ -289,7 +290,7 @@ export default class Module {
 				statement = this.definitions[ name ];
 			}
 
-			if ( statement && !statement._included ) {
+			if ( statement && !statement.isIncluded ) {
 				promise = this.expandStatement( statement );
 			}
 		}
@@ -299,14 +300,14 @@ export default class Module {
 	}
 
 	expandStatement ( statement ) {
-		if ( statement._included ) return emptyArrayPromise;
-		statement._included = true;
+		if ( statement.isIncluded ) return emptyArrayPromise;
+		statement.isIncluded = true;
 
 		let result = [];
 
 		// We have a statement, and it hasn't been included yet. First, include
 		// the statements it depends on
-		const dependencies = Object.keys( statement._dependsOn );
+		const dependencies = Object.keys( statement.dependsOn );
 
 		return sequence( dependencies, name => {
 			return this.define( name ).then( definition => {
@@ -322,12 +323,12 @@ export default class Module {
 		// then include any statements that could modify the
 		// thing(s) this statement defines
 			.then( () => {
-				return sequence( keys( statement._defines ), name => {
+				return sequence( keys( statement.defines ), name => {
 					const modifications = has( this.modifications, name ) && this.modifications[ name ];
 
 					if ( modifications ) {
 						return sequence( modifications, statement => {
-							if ( !statement._included ) {
+							if ( !statement.isIncluded ) {
 								return this.expandStatement( statement )
 									.then( statements => {
 										result.push.apply( result, statements );
@@ -349,7 +350,7 @@ export default class Module {
 
 		return sequence( this.statements, statement => {
 			// skip already-included statements
-			if ( statement._included ) return;
+			if ( statement.isIncluded ) return;
 
 			// skip import declarations
 			if ( statement.node.type === 'ImportDeclaration' ) {
diff --git a/src/Statement.js b/src/Statement.js
index f043f13..1932166 100644
--- a/src/Statement.js
+++ b/src/Statement.js
@@ -1,7 +1,19 @@
 import { keys } from './utils/object';
 
 export default class Statement {
-	constructor ( node ) {
+	constructor ( node, source, module ) {
 		this.node = node;
+		this.module = module;
+		this.source = source;
+
+		this.defines = {};
+		this.modifies = {};
+		this.dependsOn = {};
+
+		this.isIncluded = false;
+
+		this.leadingComments = []
+		this.trailingComment = null;
+		this.margin = [ 0, 0 ];
 	}
 }
diff --git a/src/ast/analyse.js b/src/ast/analyse.js
index 23ac03a..adae223 100644
--- a/src/ast/analyse.js
+++ b/src/ast/analyse.js
@@ -13,7 +13,7 @@ export default function analyse ( ast, magicString, module ) {
 		scope.add( name, false );
 
 		if ( !scope.parent ) {
-			currentTopLevelStatement._defines[ name ] = true;
+			currentTopLevelStatement.defines[ name ] = true;
 		}
 	}
 
@@ -22,7 +22,7 @@ export default function analyse ( ast, magicString, module ) {
 		scope.add( name, true );
 
 		if ( !scope.parent ) {
-			currentTopLevelStatement._defines[ name ] = true;
+			currentTopLevelStatement.defines[ name ] = true;
 		}
 	}
 
@@ -35,18 +35,6 @@ export default function analyse ( ast, magicString, module ) {
 
 		const node = statement.node;
 
-		Object.defineProperties( statement, {
-			_defines:          { value: {} },
-			_modifies:         { value: {} },
-			_dependsOn:        { value: {} },
-			_included:         { value: false, writable: true },
-			_module:           { value: module },
-			_source:           { value: magicString.snip( node.start, node.end ) }, // TODO don't use snip, it's a waste of memory
-			_margin:           { value: [ 0, 0 ] },
-			_leadingComments:  { value: [] },
-			_trailingComment:  { value: null, writable: true },
-		});
-
 		let trailing = !!previousStatement;
 
 		// TODO surely this can be neater
@@ -67,12 +55,12 @@ export default function analyse ( ast, magicString, module ) {
 
 			// attach any trailing comment to the previous statement
 			if ( trailing && !/\n/.test( magicString.slice( previousStatement.node.end, comment.start ) ) ) {
-				previousStatement._trailingComment = comment;
+				previousStatement.trailingComment = comment;
 			}
 
 			// then attach leading comments to this statement
 			else {
-				statement._leadingComments.push( comment );
+				statement.leadingComments.push( comment );
 			}
 
 			commentIndex += 1;
@@ -80,14 +68,14 @@ export default function analyse ( ast, magicString, module ) {
 		} while ( module.comments[ commentIndex ] );
 
 		// determine margin
-		const previousEnd = previousStatement ? ( previousStatement._trailingComment || previousStatement.node ).end : 0;
-		const start = ( statement._leadingComments[0] || node ).start;
+		const previousEnd = previousStatement ? ( previousStatement.trailingComment || previousStatement.node ).end : 0;
+		const start = ( statement.leadingComments[0] || node ).start;
 
 		const gap = magicString.original.slice( previousEnd, start );
 		const margin = gap.split( '\n' ).length;
 
-		if ( previousStatement ) previousStatement._margin[1] = margin;
-		statement._margin[0] = margin;
+		if ( previousStatement ) previousStatement.margin[1] = margin;
+		statement.margin[0] = margin;
 
 		walk( statement.node, {
 			enter ( node ) {
@@ -177,8 +165,8 @@ export default function analyse ( ast, magicString, module ) {
 
 				const definingScope = scope.findDefiningScope( node.name );
 
-				if ( ( !definingScope || definingScope.depth === 0 ) && !statement._defines[ node.name ] ) {
-					statement._dependsOn[ node.name ] = true;
+				if ( ( !definingScope || definingScope.depth === 0 ) && !statement.defines[ node.name ] ) {
+					statement.dependsOn[ node.name ] = true;
 				}
 			}
 
@@ -202,7 +190,7 @@ export default function analyse ( ast, magicString, module ) {
 					return;
 				}
 
-				statement._modifies[ node.name ] = true;
+				statement.modifies[ node.name ] = true;
 			}
 
 			if ( node.type === 'AssignmentExpression' ) {