<commit_before>import Ajv from "ajv"
import { CancellationToken } from "electron-builder-http"
import { debug, log, warn } from "electron-builder-util"
import { deepAssign } from "electron-builder-util/out/deepAssign"
import { statOrNull } from "electron-builder-util/out/fs"
import { httpExecutor } from "electron-builder-util/out/nodeHttpExecutor"
import { orNullIfFileNotExist } from "electron-builder-util/out/promise"
import { readFile, readJson } from "fs-extra-p"
import { safeLoad } from "js-yaml"
import JSON5 from "json5"
import * as path from "path"
import { Config } from "../metadata"
import { reactCra } from "../presets/rectCra"
import AdditionalPropertiesParams = ajv.AdditionalPropertiesParams
import ErrorObject = ajv.ErrorObject
import TypeParams = ajv.TypeParams

function getConfigFromPackageData(metadata: any | null) {
  return metadata == null ? null : metadata.build
}

async function doLoadConfig(configFile: string, projectDir: string): Promise<Config> {
  const data = await readFile(configFile, "utf8")
  let result
  if (configFile.endsWith(".json5") || configFile.endsWith(".json")) {
    result = JSON5.parse(data)
  }
  else if (configFile.endsWith(".toml")) {
    result = require("toml").parse(data)
  }
  else {
    result = safeLoad(data)
  }

  const relativePath = path.relative(projectDir, configFile)
  log(`Using ${relativePath.startsWith("..") ? configFile : relativePath} configuration file`)
  return result
}

async function loadConfig(projectDir: string, packageMetadata?: any): Promise<Config | null> {
  let data = getConfigFromPackageData(packageMetadata || (await orNullIfFileNotExist(readJson(path.join(projectDir, "package.json")))))
  if (data != null) {
    return data
  }

  for (const configFile of ["electron-builder.yml", "electron-builder.yaml", "electron-builder.json", "electron-builder.json5", "electron-builder.toml"]) {
    data = await orNullIfFileNotExist(doLoadConfig(path.join(projectDir, configFile), projectDir))
    if (data != null) {
      return data
    }
  }

  return null
}

/** @internal */
export async function getConfig(projectDir: string, configPath: string | null, packageMetadata: any | null, configFromOptions: Config | null | undefined): Promise<Config> {
  let fileOrPackageConfig
  if (configPath == null) {
    fileOrPackageConfig = await loadConfig(projectDir, packageMetadata)
  }
  else {
    fileOrPackageConfig = await doLoadConfig(path.resolve(projectDir, configPath), projectDir)
  }

  const config: Config = deepAssign(fileOrPackageConfig == null ? Object.create(null) : fileOrPackageConfig, configFromOptions)

  let extendsSpec = config.extends
  if (extendsSpec == null && extendsSpec !== null && packageMetadata != null) {
    const devDependencies = packageMetadata.devDependencies
    if (devDependencies != null && "react-scripts" in devDependencies) {
      extendsSpec = "react-cra"
      config.extends = extendsSpec
    }
  }

  if (extendsSpec == null) {
    return config
  }

  let parentConfig: Config
  if (extendsSpec === "react-cra") {
    parentConfig = await reactCra(projectDir)
  }
  else {
    let spec = extendsSpec
    if (spec.startsWith("file:")) {
      spec = spec.substring("file:".length)
    }
    parentConfig = await doLoadConfig(path.resolve(projectDir, spec), projectDir)
  }
  return deepAssign(parentConfig, config)
}

/** @internal */
export async function getElectronVersion(projectDir: string, config?: Config, projectMetadata?: any | null): Promise<string> {
  if (config == null) {
    config = await getConfig(projectDir, null, null, null)
  }
  if (config.electronVersion != null) {
    return config.electronVersion
  }
  return await computeElectronVersion(projectDir, projectMetadata)
}

/** @internal */
export async function computeElectronVersion(projectDir: string, projectMetadata?: any | null): Promise<string> {
  // projectMetadata passed only for prepacked app asar and in this case no dev deps in the app.asar
  if (projectMetadata == null) {
    for (const name of ["electron", "electron-prebuilt", "electron-prebuilt-compile"]) {
      try {
        return (await readJson(path.join(projectDir, "node_modules", name, "package.json"))).version
      }
      catch (e) {
        if (e.code !== "ENOENT") {
          warn(`Cannot read electron version from ${name} package.json: ${e.message}`)
        }
      }
    }
  }

  const packageJsonPath = path.join(projectDir, "package.json")
  const electronPrebuiltDep = findFromElectronPrebuilt(projectMetadata || await readJson(packageJsonPath))
  if (electronPrebuiltDep == null) {
    try {
      const releaseInfo = await httpExecutor.request<any>({<commit_msg>feat: resolve electron version if specified as `latest`<commit_after>import Ajv from "ajv"
import { CancellationToken } from "electron-builder-http"
import { debug, log, warn } from "electron-builder-util"
import { deepAssign } from "electron-builder-util/out/deepAssign"
import { statOrNull } from "electron-builder-util/out/fs"
import { httpExecutor } from "electron-builder-util/out/nodeHttpExecutor"
import { orNullIfFileNotExist } from "electron-builder-util/out/promise"
import { readFile, readJson } from "fs-extra-p"
import { safeLoad } from "js-yaml"
import JSON5 from "json5"
import * as path from "path"
import { Config } from "../metadata"
import { reactCra } from "../presets/rectCra"
import AdditionalPropertiesParams = ajv.AdditionalPropertiesParams
import ErrorObject = ajv.ErrorObject
import TypeParams = ajv.TypeParams

function getConfigFromPackageData(metadata: any | null) {
  return metadata == null ? null : metadata.build
}

async function doLoadConfig(configFile: string, projectDir: string): Promise<Config> {
  const data = await readFile(configFile, "utf8")
  let result
  if (configFile.endsWith(".json5") || configFile.endsWith(".json")) {
    result = JSON5.parse(data)
  }
  else if (configFile.endsWith(".toml")) {
    result = require("toml").parse(data)
  }
  else {
    result = safeLoad(data)
  }

  const relativePath = path.relative(projectDir, configFile)
  log(`Using ${relativePath.startsWith("..") ? configFile : relativePath} configuration file`)
  return result
}

async function loadConfig(projectDir: string, packageMetadata?: any): Promise<Config | null> {
  let data = getConfigFromPackageData(packageMetadata || (await orNullIfFileNotExist(readJson(path.join(projectDir, "package.json")))))
  if (data != null) {
    return data
  }

  for (const configFile of ["electron-builder.yml", "electron-builder.yaml", "electron-builder.json", "electron-builder.json5", "electron-builder.toml"]) {
    data = await orNullIfFileNotExist(doLoadConfig(path.join(projectDir, configFile), projectDir))
    if (data != null) {
      return data
    }
  }

  return null
}

/** @internal */
export async function getConfig(projectDir: string, configPath: string | null, packageMetadata: any | null, configFromOptions: Config | null | undefined): Promise<Config> {
  let fileOrPackageConfig
  if (configPath == null) {
    fileOrPackageConfig = await loadConfig(projectDir, packageMetadata)
  }
  else {
    fileOrPackageConfig = await doLoadConfig(path.resolve(projectDir, configPath), projectDir)
  }

  const config: Config = deepAssign(fileOrPackageConfig == null ? Object.create(null) : fileOrPackageConfig, configFromOptions)

  let extendsSpec = config.extends
  if (extendsSpec == null && extendsSpec !== null && packageMetadata != null) {
    const devDependencies = packageMetadata.devDependencies
    if (devDependencies != null && "react-scripts" in devDependencies) {
      extendsSpec = "react-cra"
      config.extends = extendsSpec
    }
  }

  if (extendsSpec == null) {
    return config
  }

  let parentConfig: Config
  if (extendsSpec === "react-cra") {
    parentConfig = await reactCra(projectDir)
  }
  else {
    let spec = extendsSpec
    if (spec.startsWith("file:")) {
      spec = spec.substring("file:".length)
    }
    parentConfig = await doLoadConfig(path.resolve(projectDir, spec), projectDir)
  }
  return deepAssign(parentConfig, config)
}

/** @internal */
export async function getElectronVersion(projectDir: string, config?: Config, projectMetadata?: any | null): Promise<string> {
  if (config == null) {
    config = await getConfig(projectDir, null, null, null)
  }
  if (config.electronVersion != null) {
    return config.electronVersion
  }
  return await computeElectronVersion(projectDir, projectMetadata)
}

/** @internal */
export async function computeElectronVersion(projectDir: string, projectMetadata?: any | null): Promise<string> {
  // projectMetadata passed only for prepacked app asar and in this case no dev deps in the app.asar
  if (projectMetadata == null) {
    for (const name of ["electron", "electron-prebuilt", "electron-prebuilt-compile"]) {
      try {
        return (await readJson(path.join(projectDir, "node_modules", name, "package.json"))).version
      }
      catch (e) {
        if (e.code !== "ENOENT") {
          warn(`Cannot read electron version from ${name} package.json: ${e.message}`)
        }
      }
    }
  }

  const packageJsonPath = path.join(projectDir, "package.json")
  const electronPrebuiltDep = findFromElectronPrebuilt(projectMetadata || await readJson(packageJsonPath))
  if (electronPrebuiltDep == null || electronPrebuiltDep === "latest") {
    try {
      const releaseInfo = await httpExecutor.request<any>({
{'fraction_non_alphanumeric': 0.12146952643873433, 'fraction_numerical': 0.0012741558717349756, 'mean_word_length': 4.3577929465301475, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3215915', 'n_tokens_mistral': 2793, 'n_tokens_neox': 2722, 'n_words': 708}