<commit_before>import { addValue, Arch, archFromString, deepAssign } from "builder-util"
import chalk from "chalk"
import { build as _build, Configuration, DIR_TARGET, Packager, PackagerOptions, Platform } from "app-builder-lib"
import { PublishOptions } from "electron-publish"
import yargs from "yargs"

export function createYargs() {
  return yargs
    .parserConfiguration({
      "camel-case-expansion": false,
    })
}

export interface BuildOptions extends PackagerOptions, PublishOptions {
}

export interface CliOptions extends PackagerOptions, PublishOptions {
  x64?: boolean
  ia32?: boolean
  armv7l?: boolean
  arm64?: boolean

  dir?: boolean
}

/** @private */
export function normalizeOptions(args: CliOptions): BuildOptions {
  if (args.targets != null) {
    return args
  }

  const targets = new Map<Platform, Map<Arch, Array<string>>>()

  function processTargets(platform: Platform, types: Array<string>) {
    function commonArch(currentIfNotSpecified: boolean): Array<Arch> {
      if (platform === Platform.MAC) {
        return args.x64 || currentIfNotSpecified ? [Arch.x64] : []
      }

      const result = Array<Arch>()
      if (args.x64) {
        result.push(Arch.x64)
      }
      if (args.armv7l) {
        result.push(Arch.armv7l)
      }
      if (args.arm64) {
        result.push(Arch.arm64)
      }
      if (args.ia32) {
        result.push(Arch.ia32)
      }

      return result.length === 0 && currentIfNotSpecified ? [archFromString(process.arch)] : result
    }

    let archToType = targets.get(platform)
    if (archToType == null) {
      archToType = new Map<Arch, Array<string>>()
      targets.set(platform, archToType)
    }

    if (types.length === 0) {
      const defaultTargetValue = args.dir ? [DIR_TARGET] : []
      for (const arch of commonArch(args.dir === true)) {
        archToType.set(arch, defaultTargetValue)
      }
      return
    }

    for (const type of types) {
      const suffixPos = type.lastIndexOf(":")
      if (suffixPos > 0) {
        addValue(archToType, archFromString(type.substring(suffixPos + 1)), type.substring(0, suffixPos))
      }
      else {
        for (const arch of commonArch(true)) {
          addValue(archToType, arch, type)
        }
      }
    }
  }

  if (args.mac != null) {
    processTargets(Platform.MAC, args.mac)
  }

  if (args.linux != null) {
    processTargets(Platform.LINUX, args.linux)
  }

  if (args.win != null) {
    processTargets(Platform.WINDOWS, args.win)
  }

  if (targets.size === 0) {
    processTargets(Platform.current(), [])
  }

  const result: any = {...args}
  result.targets = targets

  delete result.dir
  delete result.mac
  delete result.linux
  delete result.win

  const r = result as any
  delete r.m
  delete r.o
  delete r.l
  delete r.w
  delete r.windows
  delete r.macos
  delete r.$0
  delete r._
  delete r.version
  delete r.help
  delete r.c
  delete r.p
  delete r.pd

  delete result.ia32
  delete result.x64
  delete result.armv7l
  delete result.arm64

  let config = result.config

  // config is array when combining dot-notation values with a config file value
  // https://github.com/electron-userland/electron-builder/issues/2016
  if (Array.isArray(config)) {
    const newConfig: Configuration = {}
    for (const configItem of config) {
      if (typeof configItem === "object") {
        deepAssign(newConfig, configItem)
      }
      else if (typeof configItem === "string") {
        newConfig.extends = configItem
      }
    }

    config = newConfig
    result.config = newConfig
  }

  // AJV cannot coerce "null" string to null if string is also allowed (because null string is a valid value)
  if (config != null && typeof config !== "string") {
    if (config.extraMetadata != null) {
      coerceTypes(config.extraMetadata)
    }

    // ability to disable code sign using -c.mac.identity=null
    if (config.mac != null) {
      coerceValue(config.mac, "identity")
    }
  }

  if ("project" in r && !("projectDir" in result)) {
    result.projectDir = r.project
  }
  delete r.project

  return result as BuildOptions
}

function coerceValue(host: any, key: string): void {
  const value = host[key]
  if (value === "true") {
    host[key] = true
  }
  else if (value === "false") {
    host[key] = false
  }
  else if (value === "null") {
    host[key] = null
  }
  else if (key === "version" && typeof value === "number") {
    host[key] = value.toString()
  }
  else if (value != null && typeof value === "object") {<commit_msg>fix(nsis): fix cli config error when use Boolean value in -c.nsis config (#4528)<commit_after>import { addValue, Arch, archFromString, deepAssign } from "builder-util"
import chalk from "chalk"
import { build as _build, Configuration, DIR_TARGET, Packager, PackagerOptions, Platform } from "app-builder-lib"
import { PublishOptions } from "electron-publish"
import yargs from "yargs"

export function createYargs() {
  return yargs
    .parserConfiguration({
      "camel-case-expansion": false,
    })
}

export interface BuildOptions extends PackagerOptions, PublishOptions {
}

export interface CliOptions extends PackagerOptions, PublishOptions {
  x64?: boolean
  ia32?: boolean
  armv7l?: boolean
  arm64?: boolean

  dir?: boolean
}

/** @private */
export function normalizeOptions(args: CliOptions): BuildOptions {
  if (args.targets != null) {
    return args
  }

  const targets = new Map<Platform, Map<Arch, Array<string>>>()

  function processTargets(platform: Platform, types: Array<string>) {
    function commonArch(currentIfNotSpecified: boolean): Array<Arch> {
      if (platform === Platform.MAC) {
        return args.x64 || currentIfNotSpecified ? [Arch.x64] : []
      }

      const result = Array<Arch>()
      if (args.x64) {
        result.push(Arch.x64)
      }
      if (args.armv7l) {
        result.push(Arch.armv7l)
      }
      if (args.arm64) {
        result.push(Arch.arm64)
      }
      if (args.ia32) {
        result.push(Arch.ia32)
      }

      return result.length === 0 && currentIfNotSpecified ? [archFromString(process.arch)] : result
    }

    let archToType = targets.get(platform)
    if (archToType == null) {
      archToType = new Map<Arch, Array<string>>()
      targets.set(platform, archToType)
    }

    if (types.length === 0) {
      const defaultTargetValue = args.dir ? [DIR_TARGET] : []
      for (const arch of commonArch(args.dir === true)) {
        archToType.set(arch, defaultTargetValue)
      }
      return
    }

    for (const type of types) {
      const suffixPos = type.lastIndexOf(":")
      if (suffixPos > 0) {
        addValue(archToType, archFromString(type.substring(suffixPos + 1)), type.substring(0, suffixPos))
      }
      else {
        for (const arch of commonArch(true)) {
          addValue(archToType, arch, type)
        }
      }
    }
  }

  if (args.mac != null) {
    processTargets(Platform.MAC, args.mac)
  }

  if (args.linux != null) {
    processTargets(Platform.LINUX, args.linux)
  }

  if (args.win != null) {
    processTargets(Platform.WINDOWS, args.win)
  }

  if (targets.size === 0) {
    processTargets(Platform.current(), [])
  }

  const result: any = {...args}
  result.targets = targets

  delete result.dir
  delete result.mac
  delete result.linux
  delete result.win

  const r = result as any
  delete r.m
  delete r.o
  delete r.l
  delete r.w
  delete r.windows
  delete r.macos
  delete r.$0
  delete r._
  delete r.version
  delete r.help
  delete r.c
  delete r.p
  delete r.pd

  delete result.ia32
  delete result.x64
  delete result.armv7l
  delete result.arm64

  let config = result.config

  // config is array when combining dot-notation values with a config file value
  // https://github.com/electron-userland/electron-builder/issues/2016
  if (Array.isArray(config)) {
    const newConfig: Configuration = {}
    for (const configItem of config) {
      if (typeof configItem === "object") {
        deepAssign(newConfig, configItem)
      }
      else if (typeof configItem === "string") {
        newConfig.extends = configItem
      }
    }

    config = newConfig
    result.config = newConfig
  }

  // AJV cannot coerce "null" string to null if string is also allowed (because null string is a valid value)
  if (config != null && typeof config !== "string") {
    if (config.extraMetadata != null) {
      coerceTypes(config.extraMetadata)
    }

    // ability to disable code sign using -c.mac.identity=null
    if (config.mac != null) {
      coerceValue(config.mac, "identity")
    }

    // fix Boolean type by coerceTypes
    if (config.nsis != null) {
      coerceTypes(config.nsis);
    }
    if (config.nsisWeb != null) {
      coerceTypes(config.nsisWeb);
    }
  }

  if ("project" in r && !("projectDir" in result)) {
    result.projectDir = r.project
  }
  delete r.project

  return result as BuildOptions
}

function coerceValue(host: any, key: string): void {
  const value = host[key]
  if (value === "true") {
    host[key] = true
  }
  else if (value === "false") {
    host[key] = false
  }
  else if (value === "null") {
    host[key] = null
  }
  else if (key === "version" && typeof value === "number") {
    host[key] = value.toString()
  }
  else if (value != null && typeof value === "object") {
{'fraction_non_alphanumeric': 0.12455554358366555, 'fraction_numerical': 0.009697230901842473, 'mean_word_length': 2.78239608801956, 'pattern_counts': {'":': 4, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 2, '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': '2965563', 'n_tokens_mistral': 3044, 'n_tokens_neox': 2913, 'n_words': 787}