vite实现检测代码行数插件

55 阅读1分钟
import fs from 'node:fs'
import path from 'node:path'
import readline from 'node:readline'
import type { ViteDevServer } from 'vite'

let count = 0
/**
 * 异步统计指定文件的行数。
 *
 * @param {string} root - 要统计行数的文件的路径。
 * @returns {Promise<number>} 一个 Promise,解析为文件的行数。
 */
async function countLines(root: string): Promise<number> {
  return new Promise((resolve, reject) => {
    const strem = fs.createReadStream(root)
    const rl = readline.createInterface({
      input: strem,
      crlfDelay: Infinity,
    })
    let lineCount = 0
    rl.on('line', () => {
      lineCount++
    })

    rl.on('error', () => reject(0))

    rl.on('close', () => {
      resolve(lineCount)
    })
  })
}

const cwdPath = process.cwd()
/**
 * 递归读取指定目录下的所有文件,并统计符合条件的文件行数。
 * 如果文件行数超过指定的最大行数,则输出警告信息并退出进程。
 *
 * @param {string} srcPath - 要读取的目录路径。
 * @param {number} maxLine - 允许的最大文件行数。
 */
function readDir(srcPath: string, maxLine: number) {
  if (srcPath.includes('src/apis')) return
  const fullPath = path.join(cwdPath, srcPath)
  console.log(fullPath)

  const res = fs.readdirSync(fullPath, { withFileTypes: true })
  console.log(res)

  res.forEach((item) => {
    const fPath = path.join(cwdPath, srcPath, item.name)
    console.log(fPath)
    console.log(item.isFile())

    if (item.isFile()) {
      const match = /\.(ts|vue|js)$/.test(item.name)
      if (match) {
        countLines(fPath)
          .then((lineCount: number) => {
            if (lineCount > maxLine) {
              count += 1
              console.log(`🚨 发现 ${lineCount} 行代码的文件: ${fPath}`)
              process.exit(0)
            }
          })
          .catch((err) => {
            console.error(`读取文件 ${fPath} 时出错:`, err)
          })
      }
    } else {
      readDir(srcPath + '/' + item.name, maxLine)
    }
  })
}

export default function lineCounterPlugin(path: string, maxLine: number) {
  return {
    name: 'vite-plugin-line-counter',

    configureServer(server: ViteDevServer) {
      readDir(path, maxLine)
      server.watcher.on('all', (event, filePath) => {
        console.log(`文件 ${filePath} 发生了 ${event} 事件`)

        if (
          (event === 'change' || event === 'add') &&
          filePath.includes(path)
        ) {
          count = 0
          readDir(path, maxLine)
        }
      })
    },
  }
}