Repository: electron-userland/electron-builder
File: packages/app-builder-lib/src/node-module-collector/npmNodeModulesCollector.ts (TypeScript)

Code before:
import { log } from "builder-util"

export class NpmNodeModulesCollector extends NodeModulesCollector {
  constructor(rootDir: string) {
    super(rootDir)
  }

  getCommand(): string {
    return process.platform === "win32" ? "npm.cmd" : "npm"
  }

  getArgs(): string[] {
    return ["list", "-a", "--include", "prod", "--include", "optional", "--omit", "dev", "--json", "--long", "--silent"]
  }

  protected removeNonProductionDependencies(tree: DependencyTree): DependencyTree {
    const _deps = tree._dependencies ?? {}
    const deps = tree.dependencies ?? {}
    if (Object.keys(_deps).length > 0 && Object.keys(deps).length === 0) {
      tree.dependencies = this.allDependencies.get(`${tree.name}@${tree.version}`)?.dependencies
      tree.implicitDependenciesInjected = true
      log.debug({ name: tree.name, version: tree.version }, "injecting implicit _dependencies")
      return tree
    }

    const dependencies = Object.entries(tree.dependencies || {}).reduce<DependencyTree["dependencies"]>((acc, curr) => {
      const [packageName, dependency] = curr
      if (!_deps[packageName] || Object.keys(dependency).length === 0) {
        return acc
      }
      if (tree.implicitDependenciesInjected) {
        const { name, version, path } = dependency
        const simplifiedTree: ParsedDependencyTree = { name, version, path }
        return {
          ...acc,
          [packageName]: { ...simplifiedTree, implicitDependenciesInjected: true },
        }
      }
      return {
        ...acc,
        [packageName]: this.removeNonProductionDependencies(dependency),
      }
    }, {})

    return { ...tree, dependencies }
  }

  protected parseDependenciesTree(jsonBlob: string): NpmDependency {
    return JSON.parse(jsonBlob)
  }
}

Review comment (performance):
Will the performance of the `reduce` function be better? Currently, the `reduce` syntax seems a bit complex and not as simple or readable. Using a `for` loop appears to be more straightforward.


Code after:
import { log } from "builder-util"

export class NpmNodeModulesCollector extends NodeModulesCollector<NpmDependency, string> {
  constructor(rootDir: string) {
    super(rootDir)
  }

  getCommand(): string {
    return process.platform === "win32" ? "npm.cmd" : "npm"
  }

  getArgs(): string[] {
    return ["list", "-a", "--include", "prod", "--include", "optional", "--omit", "dev", "--json", "--long", "--silent"]
  }

  protected extractRelevantData(npmTree: NpmDependency): NpmDependency {
    const tree = super.extractRelevantData(npmTree)
    const { optionalDependencies, _dependencies } = npmTree
    return { ...tree, optionalDependencies, _dependencies }
  }

  protected extractProductionDependencyTree(tree: NpmDependency): DependencyTree {
    const _deps = tree._dependencies ?? {}

    let deps = tree.dependencies ?? {}
    let implicitDependenciesInjected = false

    if (Object.keys(_deps).length > 0 && Object.keys(deps).length === 0) {
      log.debug({ name: tree.name, version: tree.version }, "injecting implicit _dependencies")
      deps = this.allDependencies.get(`${tree.name}@${tree.version}`)?.dependencies ?? {}
      implicitDependenciesInjected = true
    }

    const dependencies = Object.entries(deps).reduce<DependencyTree["dependencies"]>((acc, curr) => {
      const [packageName, dependency] = curr
      if (!_deps[packageName] || Object.keys(dependency).length === 0) {
        return acc
      }
      if (implicitDependenciesInjected) {
        const { name, version, path, workspaces } = dependency
        const simplifiedTree: ParsedDependencyTree = { name, version, path, workspaces }
        return {
          ...acc,
          [packageName]: { ...simplifiedTree, implicitDependenciesInjected },
        }
      }
      return {
        ...acc,
        [packageName]: this.extractProductionDependencyTree(dependency),
      }
    }, {})