const _ = require(`caro`)

class CaroBack {
  constructor () {
    this._modelMap = {}
    this._hookMap = {}
  }

  _getCallerPath () {
    const prepareStackTrace = Error.prepareStackTrace
    try {
      const err = new Error()
      Error.prepareStackTrace = prepareStackTrace
      let callerFile
      let currentFile

      Error.prepareStackTrace = (err, stack) => stack

      currentFile = err.stack.shift().getFileName()

      while (err.stack.length) {
        callerFile = err.stack.shift().getFileName()

        if (currentFile !== callerFile) {
          Error.prepareStackTrace = prepareStackTrace
          return callerFile
        }
      }
    } catch (err) {
      // 跳過
    }
    Error.prepareStackTrace = prepareStackTrace
    return ``
  }

  _parseRequirePath (p) {
    const path = require(`path`)
    if (p.startsWith(`./`) || p.startsWith(`../`)) {
      const callerPath = this._getCallerPath()
      const callerDir = path.dirname(callerPath)
      p = path.join(callerDir, p)
    }
    return p
  }

  require (p, opt = {}) {
    const path = require(`path`)
    const skip = opt.skip // require 之後不要放入 ck
    opt._count = opt._count || 0

    p = this._parseRequirePath(p)

    try {
      const filename = path.basename(p).replace(path.extname(p), ``)
      const modelName = _.replaceAll(filename, `.`, `_`)
      if (!skip) {
        if (this[modelName]) {
          console.error(`model ${modelName} 已被佔用`)
          return
        }
        this[filename] = require(p)
      }
      else return require(p)
    } catch (e) {
      if (++opt._count > 100) throw Error(`載入 ${p} 失敗 - ${e}`)
      setTimeout(() => this.require(p, opt), 1)
    }
  }

  requireDir (fileOrDirPath, opt) {
    const fs = require(`fs`)
    const path = require(`path`)
    let fileCount = 0

    const requireFile = (fileOrDir) => {
      const stat = fs.statSync(fileOrDir)
      if (stat.isFile() && fileOrDir.endsWith(`.js`)) {
        this.require(fileOrDir, opt)
        fileCount++
      }
      if (stat.isDirectory()) {
        const fileArr = fs.readdirSync(fileOrDir)
        _.forEach(fileArr, (file) => {
          const filePath = path.join(fileOrDir, file)
          requireFile(filePath)
        })
      }
    }

    fileOrDirPath = this._parseRequirePath(fileOrDirPath)

    if (!fs.existsSync(fileOrDirPath)) {
      throw Error(`路徑 ${fileOrDirPath} 不存在`)
    }

    const stat = fs.statSync(fileOrDirPath)
    if (!stat.isDirectory()) {
      throw Error(`路徑 ${fileOrDirPath} 必須為資料夾`)
    }

    requireFile(fileOrDirPath)
    return fileCount
  }
}

module.exports = CaroBack

@@ -1137,25 +1137,28 @@
 ck%0A    opt._
-c
+errC
 ount = opt._
@@ -1153,25 +1153,28 @@
 ount = opt._
-c
+errC
 ount %7C%7C 0%0A%0A 
@@ -1170,16 +1170,28 @@
 unt %7C%7C 0
+ // %E8%A8%88%E6%95%B8%E8%BC%89%E5%85%A5%E9%8C%AF%E8%AA%A4%E6%AC%A1%E6%95%B8
 %0A%0A    p 
@@ -1591,17 +1591,20 @@
 (++opt._
-c
+errC
 ount %3E 1
@@ -1731,16 +1731,21 @@
 ath, opt
+ = %7B%7D
 ) %7B%0A    
@@ -1798,24 +1798,113 @@
 ire(%60path%60)%0A
+    const level = opt.level %7C%7C opt.level === 0 ? parseInt(opt.level, 10) : 1 // %E8%AE%80%E5%8F%96%E7%9A%84%E8%B3%87%E6%96%99%E5%A4%BE%E5%B1%A4%E6%95%B8%0A
     let file
@@ -1948,16 +1948,34 @@
 ileOrDir
+, currentLevel = 0
 ) =%3E %7B%0A 
@@ -2164,24 +2164,111 @@
 ectory()) %7B%0A
+        currentLevel++ // %E6%BA%96%E5%82%99%E8%AE%80%E5%8F%96%E4%B8%8B%E4%B8%80%E5%B1%A4%E8%B3%87%E6%96%99%E5%A4%BE%0A        if (level && currentLevel %3E level) return%0A
         cons
@@ -2424,24 +2424,38 @@
 ile(filePath
+, currentLevel
 )%0A        %7D)

更新 ck.requireDir 新增參數 level 讀取層數