export default function(code, id, mod1, mod2, sourceMap) { let ast; try { ast = parse(code, { ecmaVersion: 6, sourceType: 'module' }); } catch (err) { err.message += ` in ${id}`; throw err; } // analyse scopes let scope = attachScopes(ast, 'scope'); let imports = {}; ast.body.forEach(node => { if (node.type === 'ImportDeclaration') { node.specifiers.forEach(specifier => { imports[specifier.local.name] = true; }); } }); const magicString = new MagicString(code); let newImports = {}; function handleReference(node, name, keypath, parent) { if ((mod1.has(keypath) || mod2.has(keypath)) && !scope.contains(name) && !imports[name]) { if (mod2.has(keypath) && parent.__handled) { return; } let module = mod1.has(keypath) ? mod1.get(keypath) : mod2.get(keypath); let moduleName, hash; if (typeof module === 'string') { moduleName = module; hash = `${keypath}:${moduleName}:default`; } else { moduleName = module[0]; hash = `${keypath}:${moduleName}:${module[1]}`; } // prevent module from importing itself if (moduleName === id) return; const importLocalName = name === keypath ? name : makeLegalIdentifier(`$inject_${keypath}`); if (!newImports[hash]) { newImports[hash] = `import ${typeof module === 'string' ? importLocalName : `{ ${module[1]} as ${importLocalName} }`} from ${JSON.stringify(moduleName)};`; } if (name !== keypath) { magicString.overwrite(node.start, node.end, importLocalName, true); } if (mod1.has(keypath)) { node.__handled = true; } } } walk(ast, { enter(node, parent) { if (sourceMap) { magicString.addSourcemapLocation(node.start); magicString.addSourcemapLocation(node.end); } if (node.scope) scope = node.scope; // special case – shorthand properties. because node.key === node.value, // we can't differentiate once we've descended into the node if (node.type === 'Property' && node.shorthand) { const name = node.key.name; handleReference(node, name, name); return this.skip(); } if (isReference(node, parent)) { const { name, keypath } = flatten(node); handleReference(node, name, keypath, parent); } }, leave(node) { if (node.scope) scope = scope.parent; } }); const keys = Object.keys(newImports); if (!keys.length) return null; const importBlock = keys.map(hash => newImports[hash]).join('\n\n'); magicString.prepend(importBlock + '\n\n'); return { code: magicString.toString(), map: sourceMap ? magicString.generateMap() : null }; }
export default function inject ( options ) { if ( !options ) throw new Error( 'Missing options' ); const filter = createFilter( options.include, options.exclude ); let modules; if ( options.modules ) { modules = options.modules; } else { modules = assign( {}, options ); delete modules.include; delete modules.exclude; } // Fix paths on Windows if ( sep !== '/' ) { Object.keys( modules ).forEach( key => { const module = modules[ key ]; modules[ key ] = isArray( module ) ? [ module[0].split( sep ).join( '/' ), module[1] ] : module.split( sep ).join( '/' ); }); } const firstpass = new RegExp( `(?:${Object.keys( modules ).map( escape ).join( '|' )})`, 'g' ); const sourceMap = options.sourceMap !== false; return { transform ( code, id ) { if ( !filter( id ) ) return null; if ( code.search( firstpass ) == -1 ) return null; let ast; try { ast = parse( code, { ecmaVersion: 6, sourceType: 'module' }); } catch ( err ) { err.message += ` in ${id}`; throw err; } // analyse scopes let scope = attachScopes( ast, 'scope' ); let imports = {}; ast.body.forEach( node => { if ( node.type === 'ImportDeclaration' ) { node.specifiers.forEach( specifier => { imports[ specifier.local.name ] = true; }); } }); const magicString = new MagicString( code ); let newImports = {}; function handleReference ( node, name, keypath ) { if ( keypath in modules && !scope.contains( name ) && !imports[ name ] ) { let module = modules[ keypath ]; if ( typeof module === 'string' ) module = [ module, 'default' ]; // prevent module from importing itself if ( module[0] === id ) return; const hash = `${keypath}:${module[0]}:${module[1]}`; const importLocalName = name === keypath ? name : makeLegalIdentifier( `$inject_${keypath}` ); if ( !newImports[ hash ] ) { newImports[ hash ] = `import { ${module[1]} as ${importLocalName} } from '${module[0]}';`; } if ( name !== keypath ) { magicString.overwrite( node.start, node.end, importLocalName, true ); } } } walk( ast, { enter ( node, parent ) { if ( sourceMap ) { magicString.addSourcemapLocation( node.start ); magicString.addSourcemapLocation( node.end ); } if ( node.scope ) scope = node.scope; // special case – shorthand properties. because node.key === node.value, // we can't differentiate once we've descended into the node if ( node.type === 'Property' && node.shorthand ) { const name = node.key.name; handleReference( node, name, name ); return this.skip(); } if ( isReference( node, parent ) ) { const { name, keypath } = flatten( node ); handleReference( node, name, keypath ); } }, leave ( node ) { if ( node.scope ) scope = scope.parent; } }); const keys = Object.keys( newImports ); if ( !keys.length ) return null; const importBlock = keys.map( hash => newImports[ hash ] ).join( '\n\n' ); magicString.prepend( importBlock + '\n\n' ); return { code: magicString.toString(), map: sourceMap ? magicString.generateMap() : null }; } }; }
var inject = function (code, id, mod1, mod2, sourceMap) { var ast = void 0; try { ast = parse(code, { ecmaVersion: 6, sourceType: 'module' }); } catch (err) { err.message += ' in ' + id; throw err; } // analyse scopes var scope = attachScopes(ast, 'scope'); var imports = {}; ast.body.forEach(function (node) { if (node.type === 'ImportDeclaration') { node.specifiers.forEach(function (specifier) { imports[specifier.local.name] = true; }); } }); var magicString = new MagicString(code); var newImports = {}; function handleReference(node, name, keypath, parent) { if ((mod1.has(keypath) || mod2.has(keypath)) && !scope.contains(name) && !imports[name]) { if (mod2.has(keypath) && parent.__handled) { return; } var module = mod1.has(keypath) ? mod1.get(keypath) : mod2.get(keypath); var moduleName = void 0, hash = void 0; if (typeof module === 'string') { moduleName = module; hash = keypath + ':' + moduleName + ':default'; } else { moduleName = module[0]; hash = keypath + ':' + moduleName + ':' + module[1]; } // prevent module from importing itself if (moduleName === id) return; var importLocalName = name === keypath ? name : makeLegalIdentifier('$inject_' + keypath); if (!newImports[hash]) { newImports[hash] = 'import ' + (typeof module === 'string' ? importLocalName : '{ ' + module[1] + ' as ' + importLocalName + ' }') + ' from ' + JSON.stringify(moduleName) + ';'; } if (name !== keypath) { magicString.overwrite(node.start, node.end, importLocalName, true); } if (mod1.has(keypath)) { node.__handled = true; } } } walk(ast, { enter: function enter(node, parent) { if (sourceMap) { magicString.addSourcemapLocation(node.start); magicString.addSourcemapLocation(node.end); } if (node.scope) scope = node.scope; // special case – shorthand properties. because node.key === node.value, // we can't differentiate once we've descended into the node if (node.type === 'Property' && node.shorthand) { var name = node.key.name; handleReference(node, name, name); return this.skip(); } if (isReference(node, parent)) { var _flatten = flatten(node), _name = _flatten.name, keypath = _flatten.keypath; handleReference(node, _name, keypath, parent); } }, leave: function leave(node) { if (node.scope) scope = scope.parent; } }); var keys = Object.keys(newImports); if (!keys.length) return null; var importBlock = keys.map(function (hash) { return newImports[hash]; }).join('\n\n'); magicString.prepend(importBlock + '\n\n'); return { code: magicString.toString(), map: sourceMap ? magicString.generateMap() : null }; };