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

Code before:
        }, {})
      : undefined
  }

  protected resolvePath(filePath: string): string {
    try {
      const stats = fs.lstatSync(filePath)
      if (stats.isSymbolicLink()) {
        return fs.realpathSync(filePath)
      } else {
        return filePath
      }
    } catch (error: any) {
      log.debug({ message: error.message || error.stack }, "error resolving path")
      return filePath
    }
  }

  private convertToDependencyGraph(tree: DependencyTree, parentKey = "."): DependencyGraph {
    return Object.entries(tree.dependencies || {}).reduce<DependencyGraph>((acc, curr) => {
      const [packageName, dependencies] = curr
      // Skip empty dependencies (like some optionalDependencies)
      if (Object.keys(dependencies).length === 0) {
        return acc
      }
      const version = dependencies.version || ""
      const newKey = `${packageName}@${version}`
      const debugData = {
        dependency: packageName,
        version,
        path: dependencies.path,
        parentModule: tree.name,
        parentVersion: tree.version,
      }
      if (!dependencies.path) {
        log.error(debugData, "dependency path is undefined")
      }
      // Map dependency details: name, version and path to the dependency tree
      this.dependencyPathMap.set(newKey, path.normalize(this.resolvePath(dependencies.path)))
      if (!acc[parentKey]) {
        acc[parentKey] = { dependencies: [] }
      }
      acc[parentKey].dependencies.push(newKey)
      if (tree.implicitDependenciesInjected) {
        log.debug(debugData, "converted implicit dependency")
        return acc
      }

      return { ...acc, ...this.convertToDependencyGraph(dependencies, newKey) }
    }, {})
  }

Review comment (suggestion):
If the version is empty, shouldn't we throw an error directly? It shouldn't be allowed to be empty, otherwise, it could lead to issues.

Code after:
        }, {})
      : undefined
  }

  protected resolvePath(filePath: string): string {
    try {
      const stats = fs.lstatSync(filePath)
      if (stats.isSymbolicLink()) {
        return fs.realpathSync(filePath)
      } else {
        return filePath
      }
    } catch (error: any) {
      log.debug({ message: error.message || error.stack }, "error resolving path")
      return filePath
    }
  }

  private convertToDependencyGraph(tree: DependencyTree, parentKey = "."): DependencyGraph {
    return Object.entries(tree.dependencies || {}).reduce<DependencyGraph>((acc, curr) => {
      const [packageName, dependencies] = curr
      // Skip empty dependencies (like some optionalDependencies)
      if (Object.keys(dependencies).length === 0) {
        return acc
      }
      const version = dependencies.version || ""
      const newKey = `${packageName}@${version}`
      if (!dependencies.path) {
        log.error(
          {
            packageName,
            data: dependencies,
            parentModule: tree.name,
            parentVersion: tree.version,
          },
          "dependency path is undefined"
        )
        throw new Error("unable to parse `path` during `tree.dependencies` reduce")
      }
      // Map dependency details: name, version and path to the dependency tree
      this.dependencyPathMap.set(newKey, path.normalize(this.resolvePath(dependencies.path)))
      if (!acc[parentKey]) {
        acc[parentKey] = { dependencies: [] }
      }
      acc[parentKey].dependencies.push(newKey)
      if (tree.implicitDependenciesInjected) {
        log.debug(
          {
            dependency: packageName,
            version,
            path: dependencies.path,