modules.concat( externalModules ).forEach( mod => {
		// is this already named?
		if ( hasOwnProp.call( names, mod.id ) ) {
			mod.name = names[ mod.id ];
			return;
		}

		let name;
		let parts = splitPath( mod.id );
		let i = parts.length;

		while ( i-- ) {
			name = sanitize( parts.slice( i ).join( '_' ) );

			if ( !hasOwnProp.call( used, name ) ) {
				break;
			}
		}

		while ( hasOwnProp.call( used, name ) ) {
			name = '_' + name;
		}

		used[ name ] = true;
		mod.name = name;
	});
			x.specifiers.forEach( s => {
				var moduleId, mod, moduleName, specifierName, replacement, hash, isChained, separatorIndex;

				moduleId = x.id;

				if ( s.isBatch ) {
					replacement = ( bundle.moduleLookup[ moduleId ] || bundle.externalModuleLookup[ moduleId ] ).name;
				}

				else {
					specifierName = s.name;

					// If this is a chained import, get the origin
					hash = `${moduleId}@${specifierName}`;
					while ( hasOwnProp.call( bundle.chains, hash ) ) {
						hash = bundle.chains[ hash ];
						isChained = true;
					}

					if ( isChained ) {
						separatorIndex = hash.indexOf( '@' );
						moduleId = hash.substr( 0, separatorIndex );
						specifierName = hash.substring( separatorIndex + 1 );
					}

					mod = ( bundle.moduleLookup[ moduleId ] || bundle.externalModuleLookup[ moduleId ] );
					moduleName = mod && mod.name;

					if ( specifierName === 'default' ) {
						// if it's an external module, always use __default if the
						// bundle also uses named imports
						if ( !!externalModule ) {
							replacement = externalModule.needsNamed ? `${moduleName}__default` : moduleName;
						}

						// TODO We currently need to check for the existence of `mod`, because modules
						// can be skipped. Would be better to replace skipped modules with dummies
						// - see https://github.com/Rich-Harris/esperanto/issues/32
						else if ( mod ) {
							replacement = mod.identifierReplacements.default;
						}
					} else if ( !externalModule ) {
						replacement = hasOwnProp.call( conflicts, specifierName ) ?
							`${moduleName}__${specifierName}` :
							specifierName;
					} else {
						replacement = moduleName + '.' + specifierName;
					}
				}

				if ( replacement !== s.as ) {
					moduleIdentifiers[ s.as ] = replacement;
				}
			});
Example #3
0
	imports.forEach( x => {
		let moduleId = x.path;
		let name;

		moduleId = x.path;

		// use existing value
		if ( hasOwnProp.call( nameById, moduleId ) ) {
			x.name = nameById[ moduleId ];
			return;
		}

		// if user supplied a function, defer to it
		if ( userFn && ( name = userFn( moduleId ) ) ) {
			name = sanitize( name );

			if ( hasOwnProp.call( usedNames, name ) ) {
				// TODO write a test for this
				throw new Error( `Naming collision: module ${moduleId} cannot be called ${name}` );
			}
		}

		else {
			let parts = splitPath( moduleId );
			let i;
			let prefix = '';
			let candidate;

			do {
				i = parts.length;
				while ( i-- > 0 ) {
					candidate = prefix + sanitize( parts.slice( i ).join( '__' ) );

					if ( !hasOwnProp.call( usedNames, candidate ) ) {
						name = candidate;
						break;
					}
				}

				prefix += '_';
			} while ( !name );
		}

		usedNames[ name ] = true;
		nameById[ moduleId ] = name;

		x.name = name;
	});
Example #4
0
function deconflict ( name, declared ) {
	while ( hasOwnProp.call( declared, name ) ) {
		name = '_' + name;
	}

	return name;
}
function tryPath ( base, filename, userModules ) {
	const absolutePath = path.resolve( base, filename );

	if ( hasOwnProp.call( userModules, absolutePath ) ) {
		return Promise.resolve( absolutePath );
	}
	return sander.stat( absolutePath ).then( () => absolutePath );
}
Example #6
0
	mod.imports.forEach( x => {
		if ( !hasOwnProp.call( seen, x.path ) ) {
			let replacement = x.isEmpty ? `${req(x.path)};` : `var ${x.as} = ${req(x.path)};`;
			mod.body.replace( x.start, x.end, replacement );

			seen[ x.path ] = true;
		} else {
			mod.body.remove( x.start, x.next );
		}
	});
	bundle.modules.forEach( mod => {
		let x = mod.defaultExport;

		if ( x ) {
			let result;

			if ( x.hasDeclaration && x.name ) {
				result = hasOwnProp.call( conflicts, x.name ) || otherModulesDeclare( mod, x.name ) ?
					`${mod.name}__${x.name}` :
					x.name;
			} else {
				result = hasOwnProp.call( conflicts, mod.name ) || ( x.value !== mod.name && ~mod.ast._topLevelNames.indexOf( mod.name )) || otherModulesDeclare( mod, mod.name ) ?
					`${mod.name}__default` :
					mod.name;
			}

			mod.identifierReplacements.default = result;
		}
	});
	function otherModulesDeclare ( mod, replacement ) {
		var i, otherMod;

		i = bundle.modules.length;
		while ( i-- ) {
			otherMod = bundle.modules[i];

			if ( mod === otherMod ) {
				continue;
			}

			if ( hasOwnProp.call( otherMod.ast._declared, replacement ) ) {
				return true;
			}
		}
	}
	mod.exports.forEach( x => {
		var name;

		if ( x.isDefault ) {
			if ( x.type === 'namedFunction' || x.type === 'namedClass' ) {
				// if you have a default export like
				//
				//     export default function foo () {...}
				//
				// you need to rewrite it as
				//
				//     function foo () {...}
				//     exports.default = foo;
				//
				// as the `foo` reference may be used elsewhere

				// remove the `export default `, keep the rest
				body.remove( x.start, x.valueStart );
			}

			else if ( x.node.declaration && ( name = x.node.declaration.name ) ) {
				if ( name === identifierReplacements.default ) {
					body.remove( x.start, x.end );
				} else {
					let original = hasOwnProp.call( identifierReplacements, name ) ? identifierReplacements[ name ] : name;
					body.replace( x.start, x.end, `var ${identifierReplacements.default} = ${original};` );
				}
			}

			else {
				body.replace( x.start, x.valueStart, `var ${identifierReplacements.default} = ` );
			}

			return;
		}

		if ( x.hasDeclaration ) {
			if ( x.type === 'namedFunction' ) {
				shouldExportEarly[ x.name ] = true; // TODO what about `function foo () {}; export { foo }`?
			}

			body.remove( x.start, x.valueStart );
		} else {
			body.remove( x.start, x.next );
		}
	});
					return resolvePath( base, userModules, id, absolutePath, options.resolvePath ).then( absolutePath => {
						let promise = hasOwnProp.call( promiseByPath, absolutePath ) && promiseByPath[ absolutePath ];
						let cyclical = !!promise;

						if ( cyclical ) {
							// ensure all modules are set before we
							// create the bundle...
							cyclicalModules.push(
								promise.then( module => x.module = module )
							);

							// ...then short-circuit
							return;
						}

						return fetchModule( id, absolutePath ).then( module => x.module = module );
					}, function handleError ( err ) {
					}, function handleError ( err ) {
						if ( err.code === 'ENOENT' ) {
							// Most likely an external module
							let externalModule = hasOwnProp.call( externalModuleLookup, id ) && externalModuleLookup[ id ];

							if ( !externalModule ) {
								externalModule = {
									id,
									isExternal: true
								};

								externalModules.push( externalModule );
								externalModuleLookup[ id ] = externalModule;
							}

							x.module = externalModule;
						} else {
							throw err;
						}
					} );
	// infer names from default imports - e.g. with `import _ from './utils'`,
	// use '_' instead of generating a name from 'utils'
	function inferName ( x ) {
		if ( x.isDefault && !hasOwnProp.call( names, x.module.id ) && !hasOwnProp.call( used, x.as ) ) {
			names[ x.module.id ] = x.as;
			used[ x.as ] = true;
		}
	}
Example #13
0
	imports.forEach( x => {
		if ( hasOwnProp.call( inferredNames, x.path ) ) {
			x.name = inferredNames[ x.path ];
		}
	});
Example #14
0
	imports.forEach( x => {
		if ( x.as && !hasOwnProp.call( usedNames, x.as ) ) {
			inferredNames[ x.path ] = x.as;
		}
	});
export default function transformBody ( bundle, mod, body ) {
	let identifierReplacements = mod.identifierReplacements;
	let [ importedBindings, importedNamespaces ] = getReadOnlyIdentifiers( mod.imports );

	let exportNames = hasOwnProp.call( bundle.exports, mod.id ) && bundle.exports[ mod.id ];

	traverseAst( mod.ast, body, identifierReplacements, importedBindings, importedNamespaces, exportNames );

	// Remove import statements
	mod.imports.forEach( x => {
		if ( !x.passthrough ) {
			body.remove( x.start, x.next );
		}
	});

	let shouldExportEarly = {};

	// Remove export statements
	mod.exports.forEach( x => {
		var name;

		if ( x.isDefault ) {
			if ( x.type === 'namedFunction' || x.type === 'namedClass' ) {
				// if you have a default export like
				//
				//     export default function foo () {...}
				//
				// you need to rewrite it as
				//
				//     function foo () {...}
				//     exports.default = foo;
				//
				// as the `foo` reference may be used elsewhere

				// remove the `export default `, keep the rest
				body.remove( x.start, x.valueStart );
			}

			else if ( x.node.declaration && ( name = x.node.declaration.name ) ) {
				if ( name === identifierReplacements.default ) {
					body.remove( x.start, x.end );
				} else {
					let original = hasOwnProp.call( identifierReplacements, name ) ? identifierReplacements[ name ] : name;
					body.replace( x.start, x.end, `var ${identifierReplacements.default} = ${original};` );
				}
			}

			else {
				body.replace( x.start, x.valueStart, `var ${identifierReplacements.default} = ` );
			}

			return;
		}

		if ( x.hasDeclaration ) {
			if ( x.type === 'namedFunction' ) {
				shouldExportEarly[ x.name ] = true; // TODO what about `function foo () {}; export { foo }`?
			}

			body.remove( x.start, x.valueStart );
		} else {
			body.remove( x.start, x.next );
		}
	});

	// If this module exports a namespace - i.e. another module does
	// `import * from 'foo'` - then we need to make all this module's
	// exports available, using Object.defineProperty
	var indentStr = body.getIndentString();
	if ( mod._exportsNamespace ) {
		let namespaceExportBlock = `var ${mod.name} = {\n`,
			namespaceExports = [];

		mod.exports.forEach( x => {
			if ( x.hasDeclaration ) {
				namespaceExports.push( indentStr + `get ${x.name} () { return ${identifierReplacements[x.name]}; }` );
			}

			else if ( x.isDefault ) {
				namespaceExports.push( indentStr + `get default () { return ${identifierReplacements.default}; }` );
			}

			else {
				x.specifiers.forEach( s => {
					namespaceExports.push( indentStr + `get ${s.name} () { return ${s.name}; }` );
				});
			}
		});

		namespaceExportBlock += namespaceExports.join( ',\n' ) + '\n};\n\n';

		body.prepend( namespaceExportBlock );
	}

	// If this module is responsible for one of the bundle's exports
	// (it doesn't have to be the entry module, which could re-export
	// a binding from another module), we write exports here
	if ( exportNames ) {
		let exportBlock = [];

		Object.keys( exportNames ).forEach( name => {
			var exportAs = exportNames[ name ];
			exportBlock.push( `exports.${exportAs} = ${identifierReplacements[name]};` );
		});

		if ( exportBlock.length ) {
			body.trim().append( '\n\n' + exportBlock.join( '\n' ) );
		}
	}

	return body.trim();
}
		mod.ast._topLevelNames.forEach( n => {
			moduleIdentifiers[n] = hasOwnProp.call( conflicts, n ) ?
				`${mod.name}__${n}` :
				n;
		});
	function fetchModule ( moduleId, absolutePath ) {
		if ( !hasOwnProp.call( promiseByPath, absolutePath ) ) {
			promiseByPath[ absolutePath ] = (
				hasOwnProp.call( userModules, absolutePath ) ?
					Promise.resolve( userModules[ absolutePath ] ) :
					sander.readFile( absolutePath ).then( String )
			).then( function ( source ) {
				let code, ast;

				// normalise
				if ( typeof source === 'object' ) {
					code = source.code;
					ast = source.ast;
				} else {
					code = source;
					ast = null;
				}

				if ( options.transform ) {
					code = options.transform( code, absolutePath );

					if ( typeof code !== 'string' && !isThenable( code ) ) {
						throw new Error( 'transform should return String or Promise' );
					}
				}

				let module = getModule({
					id: moduleId,
					path: absolutePath,
					code,
					ast,

					// TODO should not need this
					relativePath: path.relative( base, absolutePath )
				});

				modules.push( module );
				moduleLookup[ moduleId ] = module;

				let promises = module.imports.map( x => {
					// TODO remove this, use x.module instead. more flexible, no lookups involved
					const id = resolveId( x.path, module.relativePath );

					if ( id === moduleId ) {
						throw new Error( 'A module (' + moduleId + ') cannot import itself' );
					}

					// Some modules can be skipped
					if ( skip && ~skip.indexOf( id ) ) {
						const skippedModule = {
							id,
							isSkipped: true
						};

						x.module = skippedModule;
						return skippedModule;
					}

					return resolvePath( base, userModules, id, absolutePath, options.resolvePath ).then( absolutePath => {
						let promise = hasOwnProp.call( promiseByPath, absolutePath ) && promiseByPath[ absolutePath ];
						let cyclical = !!promise;

						if ( cyclical ) {
							// ensure all modules are set before we
							// create the bundle...
							cyclicalModules.push(
								promise.then( module => x.module = module )
							);

							// ...then short-circuit
							return;
						}

						return fetchModule( id, absolutePath ).then( module => x.module = module );
					}, function handleError ( err ) {
						if ( err.code === 'ENOENT' ) {
							// Most likely an external module
							let externalModule = hasOwnProp.call( externalModuleLookup, id ) && externalModuleLookup[ id ];

							if ( !externalModule ) {
								externalModule = {
									id,
									isExternal: true
								};

								externalModules.push( externalModule );
								externalModuleLookup[ id ] = externalModule;
							}

							x.module = externalModule;
						} else {
							throw err;
						}
					} );
				});

				return Promise.all( promises )
					.then( () => module );
			});
		}

		return promiseByPath[ absolutePath ];
	}