Browse Source

replace classes with functions

gh-384
Rich-Harris 9 years ago
parent
commit
da127ffea0
  1. 18
      src/Bundle.js
  2. 60
      src/Declaration.js
  3. 10
      src/ExternalModule.js
  4. 36
      src/Module.js
  5. 19
      src/Statement.js
  6. 14
      src/ast/Scope.js
  7. 8
      src/utils/object.js

18
src/Bundle.js

@ -1,7 +1,7 @@
import Promise from 'es6-promise/lib/es6-promise/promise.js'; import Promise from 'es6-promise/lib/es6-promise/promise.js';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import first from './utils/first.js'; import first from './utils/first.js';
import { blank, keys } from './utils/object.js'; import { assign, blank, keys } from './utils/object.js';
import Module from './Module.js'; import Module from './Module.js';
import ExternalModule from './ExternalModule.js'; import ExternalModule from './ExternalModule.js';
import finalisers from './finalisers/index.js'; import finalisers from './finalisers/index.js';
@ -15,8 +15,7 @@ import collapseSourcemaps from './utils/collapseSourcemaps.js';
import callIfFunction from './utils/callIfFunction.js'; import callIfFunction from './utils/callIfFunction.js';
import { isRelative } from './utils/path.js'; import { isRelative } from './utils/path.js';
export default class Bundle { export default function Bundle ( options ) {
constructor ( options ) {
this.plugins = ensureArray( options.plugins ); this.plugins = ensureArray( options.plugins );
this.plugins.forEach( plugin => { this.plugins.forEach( plugin => {
@ -61,6 +60,7 @@ export default class Bundle {
[ 'module', 'exports' ].forEach( global => this.assumedGlobals[ global ] = true ); [ 'module', 'exports' ].forEach( global => this.assumedGlobals[ global ] = true );
} }
assign( Bundle.prototype, {
build () { build () {
// Phase 1 – discovery. We load the entry module and find which // Phase 1 – discovery. We load the entry module and find which
// modules it imports, and import those, until we have all // modules it imports, and import those, until we have all
@ -103,7 +103,7 @@ export default class Bundle {
this.orderedModules = this.sort(); this.orderedModules = this.sort();
this.deconflict(); this.deconflict();
}); });
} },
deconflict () { deconflict () {
let used = blank(); let used = blank();
@ -135,7 +135,7 @@ export default class Bundle {
declaration.name = getSafeName( declaration.name ); declaration.name = getSafeName( declaration.name );
}); });
}); });
} },
fetchModule ( id, importer ) { fetchModule ( id, importer ) {
// short-circuit cycles // short-circuit cycles
@ -161,7 +161,7 @@ export default class Bundle {
return this.fetchAllDependencies( module ).then( () => module ); return this.fetchAllDependencies( module ).then( () => module );
}); });
} },
fetchAllDependencies ( module ) { fetchAllDependencies ( module ) {
const promises = module.dependencies.map( source => { const promises = module.dependencies.map( source => {
@ -191,7 +191,7 @@ export default class Bundle {
}); });
return Promise.all( promises ); return Promise.all( promises );
} },
render ( options = {} ) { render ( options = {} ) {
const format = options.format || 'es6'; const format = options.format || 'es6';
@ -258,7 +258,7 @@ export default class Bundle {
} }
return { code, map }; return { code, map };
} },
sort () { sort () {
let seen = {}; let seen = {};
@ -340,4 +340,4 @@ export default class Bundle {
return ordered; return ordered;
} }
} });

60
src/Declaration.js

@ -1,8 +1,7 @@
import { blank, keys } from './utils/object.js'; import { assign, blank, keys } from './utils/object.js';
import run from './utils/run.js'; import run from './utils/run.js';
export default class Declaration { export default function Declaration ( node, isParam, statement ) {
constructor ( node, isParam, statement ) {
if ( node ) { if ( node ) {
if ( node.type === 'FunctionDeclaration' ) { if ( node.type === 'FunctionDeclaration' ) {
this.isFunctionDeclaration = true; this.isFunctionDeclaration = true;
@ -23,23 +22,24 @@ export default class Declaration {
this.isUsed = false; this.isUsed = false;
} }
assign( Declaration.prototype, {
addAlias ( declaration ) { addAlias ( declaration ) {
this.aliases.push( declaration ); this.aliases.push( declaration );
} },
addReference ( reference ) { addReference ( reference ) {
reference.declaration = this; reference.declaration = this;
this.name = reference.name; // TODO handle differences of opinion this.name = reference.name; // TODO handle differences of opinion
if ( reference.isReassignment ) this.isReassigned = true; if ( reference.isReassignment ) this.isReassigned = true;
} },
render ( es6 ) { render ( es6 ) {
if ( es6 ) return this.name; if ( es6 ) return this.name;
if ( !this.isReassigned || !this.isExported ) return this.name; if ( !this.isReassigned || !this.isExported ) return this.name;
return `exports.${this.name}`; return `exports.${this.name}`;
} },
run ( strongDependencies ) { run ( strongDependencies ) {
if ( this.tested ) return this.hasSideEffects; if ( this.tested ) return this.hasSideEffects;
@ -52,7 +52,7 @@ export default class Declaration {
} }
return this.hasSideEffects; return this.hasSideEffects;
} },
use () { use () {
if ( this.isUsed ) return; if ( this.isUsed ) return;
@ -62,10 +62,9 @@ export default class Declaration {
this.aliases.forEach( alias => alias.use() ); this.aliases.forEach( alias => alias.use() );
} }
} });
export class SyntheticDefaultDeclaration { export function SyntheticDefaultDeclaration ( node, statement, name ) {
constructor ( node, statement, name ) {
this.node = node; this.node = node;
this.statement = statement; this.statement = statement;
this.name = name; this.name = name;
@ -75,9 +74,10 @@ export class SyntheticDefaultDeclaration {
this.aliases = []; this.aliases = [];
} }
assign( SyntheticDefaultDeclaration.prototype, {
addAlias ( declaration ) { addAlias ( declaration ) {
this.aliases.push( declaration ); this.aliases.push( declaration );
} },
addReference ( reference ) { addReference ( reference ) {
// Bind the reference to `this` declaration. // Bind the reference to `this` declaration.
@ -87,17 +87,17 @@ export class SyntheticDefaultDeclaration {
if ( reference.name === 'default' ) return; if ( reference.name === 'default' ) return;
this.name = reference.name; this.name = reference.name;
} },
bind ( declaration ) { bind ( declaration ) {
this.original = declaration; this.original = declaration;
} },
render () { render () {
return !this.original || this.original.isReassigned ? return !this.original || this.original.isReassigned ?
this.name : this.name :
this.original.render(); this.original.render();
} },
run ( strongDependencies ) { run ( strongDependencies ) {
if ( this.original ) { if ( this.original ) {
@ -107,7 +107,7 @@ export class SyntheticDefaultDeclaration {
if ( /FunctionExpression/.test( this.node.declaration.type ) ) { if ( /FunctionExpression/.test( this.node.declaration.type ) ) {
return run( this.node.declaration.body, this.statement.scope, this.statement, strongDependencies, false ); return run( this.node.declaration.body, this.statement.scope, this.statement, strongDependencies, false );
} }
} },
use () { use () {
this.isUsed = true; this.isUsed = true;
@ -117,10 +117,9 @@ export class SyntheticDefaultDeclaration {
this.aliases.forEach( alias => alias.use() ); this.aliases.forEach( alias => alias.use() );
} }
} });
export class SyntheticNamespaceDeclaration { export function SyntheticNamespaceDeclaration ( module ) {
constructor ( module ) {
this.module = module; this.module = module;
this.name = null; this.name = null;
@ -133,9 +132,10 @@ export class SyntheticNamespaceDeclaration {
}); });
} }
assign( SyntheticNamespaceDeclaration.prototype, {
addAlias ( declaration ) { addAlias ( declaration ) {
this.aliases.push( declaration ); this.aliases.push( declaration );
} },
addReference ( reference ) { addReference ( reference ) {
// if we have e.g. `foo.bar`, we can optimise // if we have e.g. `foo.bar`, we can optimise
@ -168,7 +168,7 @@ export class SyntheticNamespaceDeclaration {
reference.declaration = this; reference.declaration = this;
this.name = reference.name; this.name = reference.name;
} },
renderBlock ( indentString ) { renderBlock ( indentString ) {
const members = keys( this.originals ).map( name => { const members = keys( this.originals ).map( name => {
@ -182,11 +182,11 @@ export class SyntheticNamespaceDeclaration {
}); });
return `var ${this.render()} = Object.freeze({\n${members.join( ',\n' )}\n});\n\n`; return `var ${this.render()} = Object.freeze({\n${members.join( ',\n' )}\n});\n\n`;
} },
render () { render () {
return this.name; return this.name;
} },
use () { use () {
keys( this.originals ).forEach( name => { keys( this.originals ).forEach( name => {
@ -195,18 +195,18 @@ export class SyntheticNamespaceDeclaration {
this.aliases.forEach( alias => alias.use() ); this.aliases.forEach( alias => alias.use() );
} }
} });
export class ExternalDeclaration { export function ExternalDeclaration ( module, name ) {
constructor ( module, name ) {
this.module = module; this.module = module;
this.name = name; this.name = name;
this.isExternal = true; this.isExternal = true;
} }
assign( ExternalDeclaration.prototype, {
addAlias () { addAlias () {
// noop // noop
} },
addReference ( reference ) { addReference ( reference ) {
reference.declaration = this; reference.declaration = this;
@ -214,7 +214,7 @@ export class ExternalDeclaration {
if ( this.name === 'default' || this.name === '*' ) { if ( this.name === 'default' || this.name === '*' ) {
this.module.suggestName( reference.name ); this.module.suggestName( reference.name );
} }
} },
render ( es6 ) { render ( es6 ) {
if ( this.name === '*' ) { if ( this.name === '*' ) {
@ -228,13 +228,13 @@ export class ExternalDeclaration {
} }
return es6 ? this.name : `${this.module.name}.${this.name}`; return es6 ? this.name : `${this.module.name}.${this.name}`;
} },
run () { run () {
return true; return true;
} },
use () { use () {
// noop? // noop?
} }
} });

10
src/ExternalModule.js

@ -1,9 +1,8 @@
import { blank } from './utils/object.js'; import { assign, blank } from './utils/object.js';
import makeLegalIdentifier from './utils/makeLegalIdentifier.js'; import makeLegalIdentifier from './utils/makeLegalIdentifier.js';
import { ExternalDeclaration } from './Declaration.js'; import { ExternalDeclaration } from './Declaration.js';
export default class ExternalModule { export default function ExternalModule ( id ) {
constructor ( id ) {
this.id = id; this.id = id;
this.name = makeLegalIdentifier( id ); this.name = makeLegalIdentifier( id );
@ -16,6 +15,7 @@ export default class ExternalModule {
this.exportsNames = false; this.exportsNames = false;
} }
assign( ExternalModule.prototype, {
suggestName ( name ) { suggestName ( name ) {
if ( !this.nameSuggestions[ name ] ) this.nameSuggestions[ name ] = 0; if ( !this.nameSuggestions[ name ] ) this.nameSuggestions[ name ] = 0;
this.nameSuggestions[ name ] += 1; this.nameSuggestions[ name ] += 1;
@ -24,7 +24,7 @@ export default class ExternalModule {
this.mostCommonSuggestion = this.nameSuggestions[ name ]; this.mostCommonSuggestion = this.nameSuggestions[ name ];
this.name = name; this.name = name;
} }
} },
traceExport ( name ) { traceExport ( name ) {
if ( name !== 'default' && name !== '*' ) { if ( name !== 'default' && name !== '*' ) {
@ -35,4 +35,4 @@ export default class ExternalModule {
this.declarations[ name ] = new ExternalDeclaration( this, name ) this.declarations[ name ] = new ExternalDeclaration( this, name )
); );
} }
} });

36
src/Module.js

@ -2,7 +2,7 @@ import { parse } from 'acorn/src/index.js';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import Statement from './Statement.js'; import Statement from './Statement.js';
import { blank, keys } from './utils/object.js'; import { assign, blank, keys } from './utils/object.js';
import { basename, extname } from './utils/path.js'; import { basename, extname } from './utils/path.js';
import getLocation from './utils/getLocation.js'; import getLocation from './utils/getLocation.js';
import makeLegalIdentifier from './utils/makeLegalIdentifier.js'; import makeLegalIdentifier from './utils/makeLegalIdentifier.js';
@ -11,8 +11,7 @@ import { SyntheticDefaultDeclaration, SyntheticNamespaceDeclaration } from './De
import { isFalsy, isTruthy } from './ast/conditions.js'; import { isFalsy, isTruthy } from './ast/conditions.js';
import { emptyBlockStatement } from './ast/create.js'; import { emptyBlockStatement } from './ast/create.js';
export default class Module { export default function Module ({ id, code, originalCode, ast, sourceMapChain, bundle }) {
constructor ({ id, code, originalCode, ast, sourceMapChain, bundle }) {
this.code = code; this.code = code;
this.originalCode = originalCode; this.originalCode = originalCode;
this.sourceMapChain = sourceMapChain; this.sourceMapChain = sourceMapChain;
@ -55,6 +54,7 @@ export default class Module {
this.strongDependencies = []; this.strongDependencies = [];
} }
assign( Module.prototype, {
addExport ( statement ) { addExport ( statement ) {
const node = statement.node; const node = statement.node;
const source = node.source && node.source.value; const source = node.source && node.source.value;
@ -127,7 +127,7 @@ export default class Module {
this.exports[ name ] = { localName: name }; this.exports[ name ] = { localName: name };
} }
} }
} },
addImport ( statement ) { addImport ( statement ) {
const node = statement.node; const node = statement.node;
@ -151,7 +151,7 @@ export default class Module {
const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name; const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;
this.imports[ localName ] = { source, name, module: null }; this.imports[ localName ] = { source, name, module: null };
}); });
} },
analyse () { analyse () {
// discover this module's imports and exports // discover this module's imports and exports
@ -165,14 +165,14 @@ export default class Module {
this.declarations[ name ] = declaration; this.declarations[ name ] = declaration;
}); });
}); });
} },
basename () { basename () {
const base = basename( this.id ); const base = basename( this.id );
const ext = extname( this.id ); const ext = extname( this.id );
return makeLegalIdentifier( ext ? base.slice( 0, -ext.length ) : base ); return makeLegalIdentifier( ext ? base.slice( 0, -ext.length ) : base );
} },
bindAliases () { bindAliases () {
keys( this.declarations ).forEach( name => { keys( this.declarations ).forEach( name => {
@ -193,7 +193,7 @@ export default class Module {
if ( otherDeclaration ) otherDeclaration.addAlias( declaration ); if ( otherDeclaration ) otherDeclaration.addAlias( declaration );
}); });
}); });
} },
bindImportSpecifiers () { bindImportSpecifiers () {
[ this.imports, this.reexports ].forEach( specifiers => { [ this.imports, this.reexports ].forEach( specifiers => {
@ -209,7 +209,7 @@ export default class Module {
const id = this.resolvedIds[ source ]; const id = this.resolvedIds[ source ];
return this.bundle.moduleById[ id ]; return this.bundle.moduleById[ id ];
}); });
} },
bindReferences () { bindReferences () {
if ( this.declarations.default ) { if ( this.declarations.default ) {
@ -238,7 +238,7 @@ export default class Module {
} }
}); });
}); });
} },
consolidateDependencies () { consolidateDependencies () {
let strongDependencies = []; let strongDependencies = [];
@ -258,7 +258,7 @@ export default class Module {
.filter( module => module !== this ); .filter( module => module !== this );
return { strongDependencies, weakDependencies }; return { strongDependencies, weakDependencies };
} },
getExports () { getExports () {
let exports = blank(); let exports = blank();
@ -278,7 +278,7 @@ export default class Module {
}); });
return keys( exports ); return keys( exports );
} },
namespace () { namespace () {
if ( !this.declarations['*'] ) { if ( !this.declarations['*'] ) {
@ -286,7 +286,7 @@ export default class Module {
} }
return this.declarations['*']; return this.declarations['*'];
} },
parse ( ast ) { parse ( ast ) {
// The ast can be supplied programmatically (but usually won't be) // The ast can be supplied programmatically (but usually won't be)
@ -417,7 +417,7 @@ export default class Module {
} }
return statements; return statements;
} },
render ( es6 ) { render ( es6 ) {
let magicString = this.magicString.clone(); let magicString = this.magicString.clone();
@ -557,7 +557,7 @@ export default class Module {
} }
return magicString.trim(); return magicString.trim();
} },
run ( safe ) { run ( safe ) {
let marked = false; let marked = false;
@ -567,7 +567,7 @@ export default class Module {
}); });
return marked; return marked;
} },
trace ( name ) { trace ( name ) {
if ( name in this.declarations ) return this.declarations[ name ]; if ( name in this.declarations ) return this.declarations[ name ];
@ -586,7 +586,7 @@ export default class Module {
} }
return null; return null;
} },
traceExport ( name ) { traceExport ( name ) {
// export { foo } from './other.js' // export { foo } from './other.js'
@ -616,4 +616,4 @@ export default class Module {
if ( declaration ) return declaration; if ( declaration ) return declaration;
} }
} }
} });

19
src/Statement.js

@ -6,9 +6,9 @@ import isFunctionDeclaration from './ast/isFunctionDeclaration.js';
import isReference from './ast/isReference.js'; import isReference from './ast/isReference.js';
import getLocation from './utils/getLocation.js'; import getLocation from './utils/getLocation.js';
import run from './utils/run.js'; import run from './utils/run.js';
import { assign } from './utils/object.js';
class Reference { function Reference ( node, scope, statement ) {
constructor ( node, scope, statement ) {
this.node = node; this.node = node;
this.scope = scope; this.scope = scope;
this.statement = statement; this.statement = statement;
@ -29,10 +29,8 @@ class Reference {
this.end = node.start + this.name.length; // can be overridden in the case of namespace members this.end = node.start + this.name.length; // can be overridden in the case of namespace members
this.rewritten = false; this.rewritten = false;
} }
}
export default class Statement { export default function Statement ( node, module, start, end ) {
constructor ( node, module, start, end ) {
this.node = node; this.node = node;
this.module = module; this.module = module;
this.start = start; this.start = start;
@ -55,6 +53,7 @@ export default class Statement {
this.isExportDeclaration && isFunctionDeclaration( node.declaration ); this.isExportDeclaration && isFunctionDeclaration( node.declaration );
} }
assign( Statement.prototype, {
firstPass () { firstPass () {
if ( this.isImportDeclaration ) return; // nothing to analyse if ( this.isImportDeclaration ) return; // nothing to analyse
@ -142,7 +141,7 @@ export default class Statement {
if ( /Function/.test( node.type ) ) readDepth -= 1; if ( /Function/.test( node.type ) ) readDepth -= 1;
} }
}); });
} },
mark () { mark () {
if ( this.isIncluded ) return; // prevent infinite loops if ( this.isIncluded ) return; // prevent infinite loops
@ -151,7 +150,7 @@ export default class Statement {
this.references.forEach( reference => { this.references.forEach( reference => {
if ( reference.declaration ) reference.declaration.use(); if ( reference.declaration ) reference.declaration.use();
}); });
} },
run ( strongDependencies, safe ) { run ( strongDependencies, safe ) {
if ( ( this.ran && this.isIncluded ) || this.isImportDeclaration || this.isFunctionDeclaration ) return; if ( ( this.ran && this.isIncluded ) || this.isImportDeclaration || this.isFunctionDeclaration ) return;
@ -161,13 +160,13 @@ export default class Statement {
this.mark(); this.mark();
return true; return true;
} }
} },
source () { source () {
return this.module.source.slice( this.start, this.end ); return this.module.source.slice( this.start, this.end );
} },
toString () { toString () {
return this.module.magicString.slice( this.start, this.end ); return this.module.magicString.slice( this.start, this.end );
} }
} });

14
src/ast/Scope.js

@ -1,4 +1,4 @@
import { blank, keys } from '../utils/object.js'; import { assign, blank, keys } from '../utils/object.js';
import Declaration from '../Declaration.js'; import Declaration from '../Declaration.js';
const extractors = { const extractors = {
@ -34,8 +34,7 @@ function extractNames ( param ) {
return names; return names;
} }
export default class Scope { export default function Scope ( options ) {
constructor ( options ) {
options = options || {}; options = options || {};
this.parent = options.parent; this.parent = options.parent;
@ -54,6 +53,7 @@ export default class Scope {
} }
} }
assign( Scope.prototype, {
addDeclaration ( node, isBlockDeclaration, isVar ) { addDeclaration ( node, isBlockDeclaration, isVar ) {
if ( !isBlockDeclaration && this.isBlockScope ) { if ( !isBlockDeclaration && this.isBlockScope ) {
// it's a `var` or function node, and this // it's a `var` or function node, and this
@ -64,21 +64,21 @@ export default class Scope {
this.declarations[ name ] = new Declaration( node, false, this.statement ); this.declarations[ name ] = new Declaration( node, false, this.statement );
}); });
} }
} },
contains ( name ) { contains ( name ) {
return this.declarations[ name ] || return this.declarations[ name ] ||
( this.parent ? this.parent.contains( name ) : false ); ( this.parent ? this.parent.contains( name ) : false );
} },
eachDeclaration ( fn ) { eachDeclaration ( fn ) {
keys( this.declarations ).forEach( key => { keys( this.declarations ).forEach( key => {
fn( key, this.declarations[ key ] ); fn( key, this.declarations[ key ] );
}); });
} },
findDeclaration ( name ) { findDeclaration ( name ) {
return this.declarations[ name ] || return this.declarations[ name ] ||
( this.parent && this.parent.findDeclaration( name ) ); ( this.parent && this.parent.findDeclaration( name ) );
} }
} });

8
src/utils/object.js

@ -1,5 +1,13 @@
export const keys = Object.keys; export const keys = Object.keys;
export function assign ( source, target ) {
keys( target ).forEach( key => {
source[ key ] = target[ key ];
});
return target;
}
export function blank () { export function blank () {
return Object.create( null ); return Object.create( null );
} }

Loading…
Cancel
Save