{
  "version": 3,
  "sources": ["../../../../../src/packages/package-store/storeController/prune.ts"],
  "sourcesContent": ["import { type Dirent, promises as fs } from 'node:fs';\nimport util from 'node:util';\nimport path from 'node:path';\nimport type { PackageFilesIndex } from '../../store.cafs/index.ts';\nimport { globalInfo, globalWarn } from '../../logger/index.ts';\nimport rimraf from '@zkochan/rimraf';\nimport { loadJsonFile } from 'load-json-file';\nimport ssri from 'ssri';\n\nconst BIG_ONE = BigInt(1) as unknown;\n\nexport type PruneOptions = {\n  cacheDir: string;\n  storeDir: string;\n};\n\nexport async function prune(\n  { cacheDir, storeDir }: PruneOptions,\n  removeAlienFiles?: boolean | undefined\n): Promise<void> {\n  const cafsDir = path.join(storeDir, 'files');\n\n  const metadataDirs = await getSubdirsSafely(cacheDir);\n\n  await Promise.all(\n    metadataDirs.map(async (metadataDir: string): Promise<void> => {\n      if (!metadataDir.startsWith('metadata')) {\n        return;\n      }\n\n      try {\n        await rimraf(path.join(cacheDir, metadataDir));\n      } catch (err: unknown) {\n        if (\n          !(\n            util.types.isNativeError(err) &&\n            'code' in err &&\n            err.code === 'ENOENT'\n          )\n        ) {\n          throw err;\n        }\n      }\n    })\n  );\n\n  await rimraf(path.join(storeDir, 'tmp'));\n\n  globalInfo('Removed all cached metadata files');\n\n  const pkgIndexFiles: string[] = [];\n\n  const indexDir = path.join(storeDir, 'index');\n\n  await Promise.all(\n    (await getSubdirsSafely(indexDir)).map(\n      async (dir: string): Promise<void> => {\n        const subdir = path.join(indexDir, dir);\n\n        await Promise.all(\n          (await fs.readdir(subdir)).map(async (fileName) => {\n            const filePath = path.join(subdir, fileName);\n\n            if (fileName.endsWith('.json')) {\n              pkgIndexFiles.push(filePath);\n            }\n          })\n        );\n      }\n    )\n  );\n\n  const removedHashes = new Set<string>();\n\n  const dirs = await getSubdirsSafely(cafsDir);\n\n  let fileCounter = 0;\n\n  await Promise.all(\n    dirs.map(async (dir: string): Promise<void> => {\n      const subdir = path.join(cafsDir, dir);\n\n      await Promise.all(\n        (await fs.readdir(subdir)).map(\n          async (fileName: string): Promise<void> => {\n            const filePath = path.join(subdir, fileName);\n\n            if (fileName.endsWith('.json')) {\n              pkgIndexFiles.push(filePath);\n              return;\n            }\n\n            const stat = await fs.stat(filePath);\n\n            if (stat.isDirectory()) {\n              if (removeAlienFiles === true) {\n                await rimraf(filePath);\n\n                globalWarn(\n                  `An alien directory has been removed from the store: ${filePath}`\n                );\n\n                fileCounter++;\n\n                return;\n              }\n\n              globalWarn(\n                `An alien directory is present in the store: ${filePath}`\n              );\n\n              return;\n            }\n\n            if (stat.nlink === 1 || stat.nlink === BIG_ONE) {\n              await fs.unlink(filePath);\n\n              fileCounter++;\n\n              removedHashes.add(\n                ssri.fromHex(`${dir}${fileName}`, 'sha512').toString()\n              );\n            }\n          }\n        )\n      );\n    })\n  );\n\n  globalInfo(`Removed ${fileCounter} file${fileCounter === 1 ? '' : 's'}`);\n\n  let pkgCounter = 0;\n\n  await Promise.all(\n    pkgIndexFiles.map(async (pkgIndexFilePath: string): Promise<void> => {\n      const { files: pkgFilesIndex } =\n        await loadJsonFile<PackageFilesIndex>(pkgIndexFilePath);\n\n      const integrity = pkgFilesIndex['package.json']?.integrity;\n\n      if (\n        typeof integrity === 'string' &&\n        removedHashes.has(integrity) === true\n      ) {\n        await fs.unlink(pkgIndexFilePath);\n\n        pkgCounter++;\n      }\n    })\n  );\n\n  globalInfo(`Removed ${pkgCounter} package${pkgCounter === 1 ? '' : 's'}`);\n}\n\nasync function getSubdirsSafely(dir: string): Promise<string[]> {\n  let entries: Dirent[];\n\n  try {\n    entries = (await fs.readdir(dir, { withFileTypes: true })) as Dirent[];\n  } catch (err: unknown) {\n    if (\n      util.types.isNativeError(err) &&\n      'code' in err &&\n      err.code === 'ENOENT'\n    ) {\n      return [];\n    }\n    throw err;\n  }\n\n  return entries\n    .filter((entry: Dirent): boolean => {\n      return entry.isDirectory();\n    })\n    .map((dir: Dirent): string => {\n      return dir.name;\n    });\n}\n"],
  "mappings": "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",
  "names": ["dir"]
}
