<commit_before>/**
 *
 * Wechaty: Wechat for ChatBots.
 * Connect ChatBots
 *
 * Class Wechaty
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
 */
import { EventEmitter } from 'events'
import * as fs          from 'fs'
import * as path        from 'path'

import {
    Config
  , HeadName
  , PuppetName
  , Sayable
}                     from './config'

import Contact        from './contact'
import FriendRequest  from './friend-request'
import Message        from './message'
import Puppet         from './puppet'
import PuppetWeb      from './puppet-web/'
import Room           from './room'
import StateMonitor   from './state-monitor'
import UtilLib        from './util-lib'

import log            from './brolog-env'

export type PuppetSetting = {
  head?:    HeadName
  puppet?:  PuppetName
  profile?: string
}

export type WechatyEventName = 'error'
                              | 'friend'
                              | 'heartbeat'
                              | 'login'
                              | 'logout'
                              | 'message'
                              | 'room-join'
                              | 'room-leave'
                              | 'room-topic'
                              | 'scan'
                              | 'EVENT_PARAM_ERROR'

export class Wechaty extends EventEmitter implements Sayable {
  private static _instance: Wechaty

  public puppet: Puppet | null

  private state = new StateMonitor<'standby', 'ready'>('Wechaty', 'standby')
  private npmVersion: string

  public uuid:        string

  public static instance(setting?: PuppetSetting) {
    if (setting && this._instance) {
      throw new Error('there has already a instance. no params will be allowed any more')
    }
    if (!this._instance) {
      this._instance = new Wechaty(setting)
    }
    return this._instance
  }

  private constructor(private setting: PuppetSetting = {}) {
    super()
    log.verbose('Wechaty', 'contructor()')

    setting.head    = setting.head    || Config.head
    setting.puppet  = setting.puppet  || Config.puppet
    setting.profile = setting.profile || Config.profile

    // setting.port    = setting.port    || Config.port

    if (setting.profile) {
      setting.profile  = /\.wechaty\.json$/i.test(setting.profile)
                        ? setting.profile
                        : setting.profile + '.wechaty.json'
    }

    this.npmVersion = require('../package.json').version

    this.uuid = UtilLib.guid()
  }

  public toString() { return 'Class Wechaty(' + this.setting.puppet + ')'}

  public version(forceNpm = false) {
    // TODO: use  git rev-parse HEAD  ?
    const dotGitPath  = path.join(__dirname, '..', '.git') // `/src/../.git`
    const gitLogCmd   = 'git'
    const gitLogArgs  = ['log', '--oneline', '-1']

    if (!forceNpm) {
      try {
        fs.statSync(dotGitPath).isDirectory()

        const ss = require('child_process')
                    .spawnSync(gitLogCmd, gitLogArgs, { cwd:  __dirname })

        if (ss.status !== 0) {
          throw new Error(ss.error)
        }

        const revision = ss.stdout
                          .toString()
                          .trim()
        return `#git[${revision}]`

      } catch (e) { /* fall safe */
        /**
         *  1. .git not exist
         *  2. git log fail
         */
        log.silly('Wechaty', 'version() test %s', e.message)
      }
    }

    return this.npmVersion<commit_msg>fix version path after build dist<commit_after>/**
 *
 * Wechaty: Wechat for ChatBots.
 * Connect ChatBots
 *
 * Class Wechaty
 *
 * Licenst: ISC
 * https://github.com/zixia/wechaty
 *
 */
import { EventEmitter } from 'events'
import * as fs          from 'fs'
import * as path        from 'path'

import {
    Config
  , HeadName
  , PuppetName
  , Sayable
}                     from './config'

import Contact        from './contact'
import FriendRequest  from './friend-request'
import Message        from './message'
import Puppet         from './puppet'
import PuppetWeb      from './puppet-web/'
import Room           from './room'
import StateMonitor   from './state-monitor'
import UtilLib        from './util-lib'

import log            from './brolog-env'

export type PuppetSetting = {
  head?:    HeadName
  puppet?:  PuppetName
  profile?: string
}

export type WechatyEventName = 'error'
                              | 'friend'
                              | 'heartbeat'
                              | 'login'
                              | 'logout'
                              | 'message'
                              | 'room-join'
                              | 'room-leave'
                              | 'room-topic'
                              | 'scan'
                              | 'EVENT_PARAM_ERROR'

export class Wechaty extends EventEmitter implements Sayable {
  private static _instance: Wechaty

  public puppet: Puppet | null

  private state = new StateMonitor<'standby', 'ready'>('Wechaty', 'standby')
  private npmVersion: string

  public uuid:        string

  public static instance(setting?: PuppetSetting) {
    if (setting && this._instance) {
      throw new Error('there has already a instance. no params will be allowed any more')
    }
    if (!this._instance) {
      this._instance = new Wechaty(setting)
    }
    return this._instance
  }

  private constructor(private setting: PuppetSetting = {}) {
    super()
    log.verbose('Wechaty', 'contructor()')

    setting.head    = setting.head    || Config.head
    setting.puppet  = setting.puppet  || Config.puppet
    setting.profile = setting.profile || Config.profile

    // setting.port    = setting.port    || Config.port

    if (setting.profile) {
      setting.profile  = /\.wechaty\.json$/i.test(setting.profile)
                        ? setting.profile
                        : setting.profile + '.wechaty.json'
    }

    this.npmVersion = require('../package.json').version

    this.uuid = UtilLib.guid()
  }

  public toString() { return 'Class Wechaty(' + this.setting.puppet + ')'}

  public version(forceNpm = false) {
    // TODO: use  git rev-parse HEAD  ?
    const dotGitPath  = path.join(__dirname, '..', '..', '.git') // `/dist/src/../../.git`
    const gitLogCmd   = 'git'
    const gitLogArgs  = ['log', '--oneline', '-1']

    if (!forceNpm) {
      try {
        fs.statSync(dotGitPath).isDirectory()

        const ss = require('child_process')
                    .spawnSync(gitLogCmd, gitLogArgs, { cwd:  __dirname })

        if (ss.status !== 0) {
          throw new Error(ss.error)
        }

        const revision = ss.stdout
                          .toString()
                          .trim()
        return `#git[${revision}]`

      } catch (e) { /* fall safe */
        /**
         *  1. .git not exist
         *  2. git log fail
         */
        log.silly('Wechaty', 'version() test %s', e.message)
      }
    }

    return this.npmVersion
{'fraction_non_alphanumeric': 0.1215556831228473, 'fraction_numerical': 0.001148105625717566, 'mean_word_length': 1.6548571428571428, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '2524292', 'n_tokens_mistral': 2057, 'n_tokens_neox': 2004, 'n_words': 498}