Repository: electron-userland/electron-builder
File: packages/app-builder-lib/src/targets/nsis/nsisUtil.ts (TypeScript)

Code before:
export interface PackArchResult {
  fileInfo: PackageFileInfo
  unpackedSize: number
}

export class AppPackageHelper {
  private readonly archToResult = new Map<Arch, Promise<PackArchResult>>()
  private readonly infoToIsDelete = new Map<PackageFileInfo, boolean>()

  /** @private */
  refCount = 0

  constructor(private readonly elevateHelper: CopyElevateHelper) {}

  async packArch(arch: Arch, target: NsisTarget): Promise<PackArchResult> {
    let resultPromise = this.archToResult.get(arch)
    if (resultPromise == null) {
      const appOutDir = target.archs.get(arch)!
      resultPromise = this.elevateHelper
        .copy(appOutDir, target)
        .then(() => dirSize(appOutDir))
        .then(unpackedSize =>
          target.buildAppPackage(appOutDir, arch).then(fileInfo => ({
            fileInfo,
            unpackedSize,
          }))
        )
      this.archToResult.set(arch, resultPromise)
    }

    const result = await resultPromise
    const { fileInfo: info } = result
    if (target.isWebInstaller) {
      this.infoToIsDelete.set(info, false)
    } else if (!this.infoToIsDelete.has(info)) {
      this.infoToIsDelete.set(info, true)
    }
    return result
  }

  async finishBuild(): Promise<any> {
    if (--this.refCount > 0) {
      return
    }

    const filesToDelete: Array<string> = []
    for (const [info, isDelete] of this.infoToIsDelete.entries()) {
      if (isDelete) {
        filesToDelete.push(info.path)
      }
    }

Review comment (refactor):
`buildAppPackage` seems to modify the `appOutDir` again, after `dirSize` has been called. (Also can't guarantee if that functionality will be changed in the future.)

What are your thoughts on this? It feels more future-proof
```
      resultPromise = this.elevateHelper
        .copy(appOutDir, target)
        .then(() => target.buildAppPackage(appOutDir, arch))
        .then(async fileInfo => ({
            fileInfo,
            unpackedSize: await dirSize(appOutDir),
          }))
```

Code after:
export interface PackArchResult {
  fileInfo: PackageFileInfo
  unpackedSize: number
}

export class AppPackageHelper {
  private readonly archToResult = new Map<Arch, Promise<PackArchResult>>()
  private readonly infoToIsDelete = new Map<PackageFileInfo, boolean>()

  /** @private */
  refCount = 0

  constructor(private readonly elevateHelper: CopyElevateHelper) {}

  async packArch(arch: Arch, target: NsisTarget): Promise<PackArchResult> {
    let resultPromise = this.archToResult.get(arch)
    if (resultPromise == null) {
      const appOutDir = target.archs.get(arch)!
      resultPromise = this.elevateHelper
        .copy(appOutDir, target)
        .then(() => target.buildAppPackage(appOutDir, arch))
        .then(async fileInfo => ({
          fileInfo,
          unpackedSize: await dirSize(appOutDir),
        }))
      this.archToResult.set(arch, resultPromise)
    }

    const result = await resultPromise
    const { fileInfo: info } = result
    if (target.isWebInstaller) {
      this.infoToIsDelete.set(info, false)
    } else if (!this.infoToIsDelete.has(info)) {
      this.infoToIsDelete.set(info, true)
    }
    return result
  }

  async finishBuild(): Promise<any> {
    if (--this.refCount > 0) {
      return
    }

    const filesToDelete: Array<string> = []
    for (const [info, isDelete] of this.infoToIsDelete.entries()) {
      if (isDelete) {
        filesToDelete.push(info.path)
      }
    }

    await Promise.all(filesToDelete.map(it => fs.unlink(it)))