{"version":3,"file":"transform.cjs","names":["getByteSize","getChunkId"],"sources":["../src/transform.ts"],"sourcesContent":["import path from 'path';\nimport type {\n  Stats,\n  AssetStats,\n  ChunkStats,\n  ModuleStats,\n} from 'rollup-plugin-stats/extract';\n\nimport { getByteSize, getChunkId } from './utils';\n\n// https://github.com/relative-ci/bundle-stats/blob/master/packages/plugin-webpack-filter/src/index.ts\nexport type WebpackStatsFilteredAsset = {\n  name: string;\n  size?: number;\n};\n\nexport interface WebpackStatsFilteredChunk {\n  id: number | string;\n  entry: boolean;\n  initial: boolean;\n  files?: Array<string>;\n  names?: Array<string>;\n}\n\nexport interface WebpackStatsFilteredModule {\n  name: string;\n  size?: number;\n  chunks: Array<string | number>;\n}\n\nexport interface WebpackStatsFilteredConcatenatedModule {\n  name: string;\n  size?: number;\n}\n\nexport interface WebpackStatsFilteredRootModule extends WebpackStatsFilteredModule {\n  modules?: Array<WebpackStatsFilteredConcatenatedModule>;\n}\n\nexport interface WebpackStatsFiltered {\n  builtAt: number;\n  hash?: string;\n  assets: Array<WebpackStatsFilteredAsset>;\n  chunks: Array<WebpackStatsFilteredChunk>;\n  modules: Array<WebpackStatsFilteredRootModule>;\n}\n\nexport type ChunksIssuers = Record<string, Array<ChunkStats>>;\n\n/**\n * Recursivily check if a chunk is async based on the chunks issuers\n */\nexport const lookupChunkAsync = (\n  chunksIssuers: ChunksIssuers,\n  chunk: ChunkStats,\n  processedChunks: Array<string> = [],\n  cache: Map<string, boolean> = new Map()\n): boolean => {\n  const cached = cache.get(chunk.fileName);\n  if (cached !== undefined) {\n    return cached;\n  }\n\n  const result = lookupChunkAsyncUncached(\n    chunksIssuers,\n    chunk,\n    processedChunks,\n    cache\n  );\n\n  cache.set(chunk.fileName, result);\n  return result;\n};\n\nconst lookupChunkAsyncUncached = (\n  chunksIssuers: ChunksIssuers,\n  chunk: ChunkStats,\n  processedChunks: Array<string>,\n  cache: Map<string, boolean>\n): boolean => {\n  // When the chunks are having a circular dependency, return true to continue the recursive check\n  if (processedChunks.includes(chunk.fileName)) {\n    return true;\n  }\n\n  if (chunk.isEntry) {\n    return false;\n  }\n\n  if (chunk.isDynamicEntry) {\n    return true;\n  }\n\n  const chunkIssuers = chunksIssuers[chunk.fileName];\n\n  /**\n   * A sync chunk without issuer chunks, is sync\n   */\n  if (!chunkIssuers) {\n    return false;\n  }\n\n  const syncChunksIssuers = chunkIssuers.filter((chunkIssuer) => {\n    return chunkIssuer.isDynamicEntry === false;\n  });\n\n  /**\n   * A sync chunk with all the chunk issuer async, is async\n   */\n  if (syncChunksIssuers.length === 0) {\n    return true;\n  }\n\n  /**\n   * Recursively lookup for sync loads on the 2nd level issuers\n   * - if at least one issuer is sync, the chunk is sync\n   * - if none of the issuers are sync, the chunk is async\n   */\n  const nextProcessed = [...processedChunks, chunk.fileName];\n\n  return syncChunksIssuers.every((issuer) =>\n    lookupChunkAsync(chunksIssuers, issuer, nextProcessed, cache)\n  );\n};\n\ntype AssetSource = ChunkStats | AssetStats;\ntype ChunkSource = ChunkStats;\ntype ModuleSource = { fileName: string } & ModuleStats;\n\n/**\n * Store transformed sources\n */\nclass TransformSources {\n  constructor() {\n    this.entries = {};\n  }\n\n  entries: Record<string, unknown> = {};\n\n  push(id: string, source: AssetSource | ChunkSource | ModuleSource) {\n    this.entries[id] = source;\n  }\n\n  /**\n   * Get asset source\n   */\n  getByAsset = (asset: WebpackStatsFilteredAsset): AssetSource => {\n    return this.entries[asset.name] as AssetSource;\n  };\n\n  /**\n   * Get chunk source\n   */\n  getByChunk = (chunk: WebpackStatsFilteredChunk): ChunkSource => {\n    return this.entries[chunk.id] as ChunkSource;\n  };\n\n  /**\n   * Get module source\n   */\n  getByModule = (module: WebpackStatsFilteredModule): ModuleSource => {\n    return this.entries[module.name] as ModuleSource;\n  };\n}\n\nexport type TransformCallback = (\n  stats: WebpackStatsFiltered,\n  sources: TransformSources,\n  bundle: Stats\n) => WebpackStatsFiltered;\n\nconst defaultTransform: TransformCallback = (stats) => stats;\n\nexport type BundleTransformOptions = {\n  /**\n   * Extract module original size or rendered size\n   * default: false\n   */\n  moduleOriginalSize?: boolean;\n  /**\n   * Callback function to access and mutate the resulting stats after the transformation\n   */\n  transform?: TransformCallback;\n};\n\nexport const bundleToWebpackStats = (\n  bundle: Stats,\n  pluginOptions?: BundleTransformOptions\n): WebpackStatsFiltered => {\n  const options = {\n    moduleOriginalSize: false,\n    ...pluginOptions,\n  } satisfies BundleTransformOptions;\n  const { moduleOriginalSize, transform = defaultTransform } = options;\n\n  const assets: Array<WebpackStatsFilteredAsset> = [];\n  const chunks: Array<WebpackStatsFilteredChunk> = [];\n  const moduleByFileName: Record<string, WebpackStatsFilteredModule> = {};\n  const sources = new TransformSources();\n  const chunksIssuers: ChunksIssuers = {};\n\n  const entries = Object.values(bundle);\n\n  // Collect metadata\n  entries.forEach((entry) => {\n    if (entry.type === 'chunk') {\n      entry.imports?.forEach((chunkImportFileName) => {\n        // Skip circular references\n        if (\n          chunksIssuers[entry.fileName]?.find(\n            (chunkIssuer) => chunkIssuer.fileName === chunkImportFileName\n          )\n        ) {\n          return;\n        }\n\n        if (!chunksIssuers[chunkImportFileName]) {\n          chunksIssuers[chunkImportFileName] = [];\n        }\n\n        chunksIssuers[chunkImportFileName].push(entry);\n      });\n    }\n  });\n\n  // Process data\n  entries.forEach((entry) => {\n    if (entry.type === 'chunk') {\n      assets.push({\n        name: entry.fileName,\n        size: getByteSize(entry.code),\n      });\n      sources.push(entry.fileName, entry);\n\n      const chunkId = getChunkId(entry);\n      const chunkAsync = lookupChunkAsync(chunksIssuers, entry);\n\n      chunks.push({\n        id: chunkId,\n        entry: entry.isEntry,\n        initial: !chunkAsync,\n        files: [entry.fileName],\n        names: [entry.name],\n      });\n      sources.push(chunkId, entry);\n\n      Object.entries(entry.modules).forEach(([modulePath, moduleInfo]) => {\n        // Remove unexpected rollup null prefix\n        const normalizedModulePath = modulePath.replace('\\u0000', '');\n\n        const relativeModulePath = path.relative(\n          process.cwd(),\n          normalizedModulePath\n        );\n\n        // Match webpack output - add current directory prefix for child modules\n        const relativeModulePathWithPrefix = relativeModulePath.match(/^\\.\\./)\n          ? relativeModulePath\n          : `.${path.sep}${relativeModulePath}`;\n\n        const moduleEntry = moduleByFileName[relativeModulePathWithPrefix];\n\n        if (moduleEntry) {\n          moduleEntry.chunks.push(chunkId);\n        } else {\n          moduleByFileName[relativeModulePathWithPrefix] = {\n            name: relativeModulePathWithPrefix,\n            size: moduleOriginalSize\n              ? moduleInfo.originalLength\n              : moduleInfo.renderedLength,\n            chunks: [chunkId],\n          };\n          sources.push(relativeModulePathWithPrefix, {\n            fileName: modulePath,\n            ...moduleInfo,\n          });\n        }\n      });\n    } else if (entry.type === 'asset') {\n      assets.push({\n        name: entry.fileName,\n        size: getByteSize(entry.source),\n      });\n      sources.push(entry.fileName, entry);\n    } else {\n      // noop for unknown types\n    }\n  });\n\n  const stats: WebpackStatsFiltered = {\n    builtAt: Date.now(),\n    assets,\n    chunks,\n    modules: Object.values(moduleByFileName),\n  };\n\n  let result: WebpackStatsFiltered;\n\n  try {\n    result = transform(stats, sources, bundle);\n  } catch (error) {\n    console.error(\n      'Custom transform failed! Returning stats without any transforms.',\n      error\n    );\n    result = stats;\n  }\n\n  return result;\n};\n"],"mappings":"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"}