code: function bundleInfoFromAssetEntry(entry) {
    var pathParts = entry.split('/').filter(Boolean);
  
    var bundleName = pathParts.shift();
    // If the bundle name starts with a "@", then we have a scoped package[1]
    // so we want to grab the next path part to complete the bundle name.
    // [1]:https://docs.npmjs.com/misc/scope
    if (bundleName && bundleName[0] === '@') {
      if (!pathParts.length) {
        return { isValid: false };
      }
      bundleName = [bundleName, pathParts.shift()].join('/');
    }
    var assetName = pathParts.pop();
  
    // If there is no assetName, then we have a directory per the rules of
    // walk-sync. And, if there are no pathParts left we have a root directory.
    // https://github.com/joliss/node-walk-sync/blob/master/README.md#usage
    var isNewBundle = !assetName && pathParts.length === 0;
  
    // Find the file extension and strip off the leading '.'
    var assetType;
    if (assetName) {
      assetType = path.extname(assetName).replace(/^\./, '') || undefined;
    }
  
    return {
      isValid: isNewBundle || Boolean(bundleName && assetType),
      isNewBundle,
      bundleName,
      assetName,
      assetType
    };
  }
docs: @typedef {Object} BundleInfo
  @property {boolean} isValid - true if we have a valid new bundle name or a bundle and asset name
  @property {boolean} isNewBundle - true if this entry is just a bundle name
  @property {string} bundleName
  @property {string=} assetName
  @property {string=} assetType - asset extension
  
  @private
  @param {string} entry
  @returns {BundleInfo}