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

Code before:
  const helperNPPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper NP.app`, "Contents", "Info.plist")
  const helperRendererPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Renderer).app`, "Contents", "Info.plist")
  const helperPluginPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Plugin).app`, "Contents", "Info.plist")
  const helperGPUPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (GPU).app`, "Contents", "Info.plist")
  const helperLoginPlistFilename = path.join(loginItemPath, `${electronBranding.productName} Login Helper.app`, "Contents", "Info.plist")

  const safeParsePlistFile = async (filePath: string): Promise<PlistValue | null> => {
    if (!fs.existsSync(filePath)) {
      return null
    }
    return await parsePlistFile(filePath)
  }

  const appPlist = (await safeParsePlistFile(appPlistFilename)) as PlistObject
  if (appPlist == null) {
    throw new Error("corrupted Electron dist")
  }

  // Replace the multiple parsePlistFile calls with:
  const helperPlist = (await safeParsePlistFile(helperPlistFilename)) as PlistObject
  const helperEHPlist = (await safeParsePlistFile(helperEHPlistFilename)) as string | null
  const helperNPPlist = (await safeParsePlistFile(helperNPPlistFilename)) as string | null
  const helperRendererPlist = (await safeParsePlistFile(helperRendererPlistFilename)) as string | null
  const helperPluginPlist = (await safeParsePlistFile(helperPluginPlistFilename)) as string | null
  const helperGPUPlist = (await safeParsePlistFile(helperGPUPlistFilename)) as string | null
  const helperLoginPlist = (await safeParsePlistFile(helperLoginPlistFilename)) as PlistObject | null

  const buildMetadata = packager.config

  /**
   * Configure bundleIdentifier for the generic Electron Helper process
   *
   * This was the only Helper in Electron 5 and before. Allow users to configure
   * the bundleIdentifier for continuity.
   */

  const oldHelperBundleId = (buildMetadata as any)["helper-bundle-id"]
  if (oldHelperBundleId != null) {
    log.warn("build.helper-bundle-id is deprecated, please set as build.mac.helperBundleId")
  }

  const defaultAppId = packager.platformSpecificBuildOptions.appId
  const cfBundleIdentifier = filterCFBundleIdentifier((isMas ? packager.config.mas?.appId : defaultAppId) || defaultAppId || appInfo.macBundleIdentifier)

  const defaultHelperId = packager.platformSpecificBuildOptions.helperBundleId
  const helperBundleIdentifier = filterCFBundleIdentifier(
    (isMas ? packager.config.mas?.helperBundleId : defaultHelperId) || defaultHelperId || oldHelperBundleId || `${cfBundleIdentifier}.helper`
  )

  appPlist.CFBundleIdentifier = cfBundleIdentifier


Review comment (suggestion):
I'm really not a fan of this casting. If you make the function generic, you won't need to worry about casting everything to `string` or `PlistObject`. I'm also not sure I understand the logic here. Why are some `string` and others `PlistObject`. Shouldn't they all be returning the same type?

```
export async function parsePlistFile<T>(file: string): Promise<T> {

```

Code after:
  const helperNPPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper NP.app`, "Contents", "Info.plist")
  const helperRendererPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Renderer).app`, "Contents", "Info.plist")
  const helperPluginPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (Plugin).app`, "Contents", "Info.plist")
  const helperGPUPlistFilename = path.join(frameworksPath, `${electronBranding.productName} Helper (GPU).app`, "Contents", "Info.plist")
  const helperLoginPlistFilename = path.join(loginItemPath, `${electronBranding.productName} Login Helper.app`, "Contents", "Info.plist")

  const safeParsePlistFile = async (filePath: string): Promise<PlistObject | null> => {
    if (!fs.existsSync(filePath)) {
      return null
    }
    return await parsePlistFile(filePath)
  }

  const appPlist = (await safeParsePlistFile(appPlistFilename))!
  if (appPlist == null) {
    throw new Error("corrupted Electron dist")
  }

  // Replace the multiple parsePlistFile calls with:
  const helperPlist = await safeParsePlistFile(helperPlistFilename)
  const helperEHPlist = await safeParsePlistFile(helperEHPlistFilename)
  const helperNPPlist = await safeParsePlistFile(helperNPPlistFilename)
  const helperRendererPlist = await safeParsePlistFile(helperRendererPlistFilename)
  const helperPluginPlist = await safeParsePlistFile(helperPluginPlistFilename)
  const helperGPUPlist = await safeParsePlistFile(helperGPUPlistFilename)
  const helperLoginPlist = await safeParsePlistFile(helperLoginPlistFilename)

  const buildMetadata = packager.config

  /**
   * Configure bundleIdentifier for the generic Electron Helper process
   *
   * This was the only Helper in Electron 5 and before. Allow users to configure
   * the bundleIdentifier for continuity.
   */

  const oldHelperBundleId = (buildMetadata as any)["helper-bundle-id"]
  if (oldHelperBundleId != null) {
    log.warn("build.helper-bundle-id is deprecated, please set as build.mac.helperBundleId")
  }

  const defaultAppId = packager.platformSpecificBuildOptions.appId
  const cfBundleIdentifier = filterCFBundleIdentifier((isMas ? packager.config.mas?.appId : defaultAppId) || defaultAppId || appInfo.macBundleIdentifier)

  const defaultHelperId = packager.platformSpecificBuildOptions.helperBundleId
  const helperBundleIdentifier = filterCFBundleIdentifier(
    (isMas ? packager.config.mas?.helperBundleId : defaultHelperId) || defaultHelperId || oldHelperBundleId || `${cfBundleIdentifier}.helper`
  )

  appPlist.CFBundleIdentifier = cfBundleIdentifier