<commit_before>/*
* @adonisjs/ace
*
* (c) <NAME> <<EMAIL>>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import * as getopts from 'getopts'

import { Parser } from '../Parser'
import { Manifest } from '../Manifest'
import { validateCommand } from '../utils/validateCommand'
import { printHelp, printHelpFor } from '../utils/help'
import {
  CommandConstructorContract,
  CommandFlag,
  GlobalFlagHandler,
  ManifestCommand,
  ManifestNode,
} from '../Contracts'

/**
 * Ace kernel class is used to register, find and invoke commands by
 * parsing `process.argv.splice(2)` value.
 */
export class Kernel {
  /**
   * List of registered commands
   */
  public commands: { [name: string]: CommandConstructorContract } = {}

  /**
   * Reference to commands defined inside the manifest file. This only exists
   * when you call [[Kernel.useManifest]].
   */
  public manifestCommands?: ManifestNode

  /**
   * List of registered flags
   */
  public flags: { [name: string]: CommandFlag & { handler: GlobalFlagHandler } } = {}

  /**
   * Reference to the manifest instance. When this exists, the kernel
   * will give prefrence to the manifest file over the registered
   * commands
   */
  private _manifest?: Manifest

  /**
   * Executing global flag handlers. The global flag handlers are
   * not async as of now, but later we can look into making them
   * async.
   */
  private _executeGlobalFlagsHandlers (
    options: getopts.ParsedOptions,
    command?: CommandConstructorContract,
  ) {
    const globalFlags = Object.keys(this.flags)

    globalFlags.forEach((name) => {
      const value = options[name]
      if (value === undefined) {
        return
      }

      if ((typeof (value) === 'string' || Array.isArray(value)) && !value.length) {
        return
      }

      this.flags[name].handler(options[name], options, command)
    })
  }

  /**
   * Register an array of commands
   */
  public register (commands: CommandConstructorContract[]): this {
    commands.forEach((command) => {
      validateCommand(command)
      this.commands[command.commandName] = command
    })

    return this
  }

  /**
   * Returns an array of command names suggestions for a given name.
   */
  public getSuggestions (name: string, distance = 3): string[] {
    const levenshtein = require('fast-levenshtein')
    return Object.keys(this.commands).filter((commandName) => {
      return levenshtein.get(name, commandName) <= distance
    })
  }

  /**
   * Register a global flag to be set on any command. The flag callback is
   * executed before executing the registered command.
   */
  public flag (
    name: string,
    handler: GlobalFlagHandler,
    options: Partial<Pick<CommandFlag, Exclude<keyof CommandFlag, 'name'>>>,
  ): this {
    this.flags[name] = Object.assign({ name, handler, type: 'boolean' }, options)
    return this
  }

  /**
   * Finds the command from the command line argv array. If command for
   * the given name doesn't exists, then it will return `null`.
   */
  public find (argv: string[]): CommandConstructorContract | null {
    /**<commit_msg>fix: getSuggestions must consider manifest commands over commands<commit_after>/*
* @adonisjs/ace
*
* (c) <NAME> <<EMAIL>>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import * as getopts from 'getopts'

import { Parser } from '../Parser'
import { Manifest } from '../Manifest'
import { validateCommand } from '../utils/validateCommand'
import { printHelp, printHelpFor } from '../utils/help'
import {
  CommandConstructorContract,
  CommandFlag,
  GlobalFlagHandler,
  ManifestCommand,
  ManifestNode,
} from '../Contracts'

/**
 * Ace kernel class is used to register, find and invoke commands by
 * parsing `process.argv.splice(2)` value.
 */
export class Kernel {
  /**
   * List of registered commands
   */
  public commands: { [name: string]: CommandConstructorContract } = {}

  /**
   * Reference to commands defined inside the manifest file. This only exists
   * when you call [[Kernel.useManifest]].
   */
  public manifestCommands?: ManifestNode

  /**
   * List of registered flags
   */
  public flags: { [name: string]: CommandFlag & { handler: GlobalFlagHandler } } = {}

  /**
   * Reference to the manifest instance. When this exists, the kernel
   * will give prefrence to the manifest file over the registered
   * commands
   */
  private _manifest?: Manifest

  /**
   * Executing global flag handlers. The global flag handlers are
   * not async as of now, but later we can look into making them
   * async.
   */
  private _executeGlobalFlagsHandlers (
    options: getopts.ParsedOptions,
    command?: CommandConstructorContract,
  ) {
    const globalFlags = Object.keys(this.flags)

    globalFlags.forEach((name) => {
      const value = options[name]

      /**
       * Flag was not specified
       */
      if (value === undefined) {
        return
      }

      /**
       * Flag was not specified, but `getops` will return empty array or
       * empty string, when we coerce flag to be a string or array
       */
      if ((typeof (value) === 'string' || Array.isArray(value)) && !value.length) {
        return
      }

      /**
       * Calling the handler
       */
      this.flags[name].handler(options[name], options, command)
    })
  }

  /**
   * Register an array of commands
   */
  public register (commands: CommandConstructorContract[]): this {
    commands.forEach((command) => {
      validateCommand(command)
      this.commands[command.commandName] = command
    })

    return this
  }

  /**
   * Returns an array of command names suggestions for a given name.
   */
  public getSuggestions (name: string, distance = 3): string[] {
    const levenshtein = require('fast-levenshtein')
    const commands = this.manifestCommands ? this.manifestCommands : this.commands
    return Object.keys(commands).filter((commandName) => {
      return levenshtein.get(name, commandName) <= distance
    })
  }

  /**
   * Register a global flag to be set on any command. The flag callback is
   * executed before executing the registered command.
   */
  public flag (
    name: string,
    handler: GlobalFlagHandler,
    options: Partial<Pick<CommandFlag, Exclude<keyof CommandFlag, 'name'>>>,
  ): this {
    this.flags[name] = Object.assign({ name, handler, type: 'boolean' }, options)
    return this
  }

  /**
   * Finds the command from the command line argv array. If command for
   * the given name doesn't exists, then it will return `null`.
   */
  public find (argv: string[]): CommandConstructorContract | null {
    /**
{'fraction_non_alphanumeric': 0.11379821958456973, 'fraction_numerical': 0.0005934718100890207, 'mean_word_length': 3.04136690647482, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 21, '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': '5244715', 'n_tokens_mistral': 1907, 'n_tokens_neox': 1863, 'n_words': 634}