当前位置: 首页 > article >正文

vue文件转AST,并恢复成vue文件(适用于antdv版本升级)

vue文件转AST,并恢复成vue文件---antdvV3升级V4

  • vue文件转AST,重新转回原文件过程
    • 如何获取项目路径
    • 读取项目文件,判断文件类型
    • 分别获取vue文件 template js(vue2和vue3)
    • 处理vue 文件template部分
    • 处理vue script部分
    • utils--transform.ts(主要转换函数)
    • utils--- antdv3_4
    • utils--excapeRe.ts
    • 思路流程图

vue文件转AST,重新转回原文件过程

## 项目结构![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7203466177fc4b1398d21bb31b83b487.png)
将打包后的dist上传到node,在本地安装。建议安装全局,方便全局使用。
安装:

npm install @my-cli -g

检查是否安装成功

 bdi-cli  --help . 

使用: < path > 替换成项目绝对路径

bdi-cli --antdv <path>

如何获取项目路径

  1. 配置bin
#!/usr/bin/env node

import {
    program } from 'commander';
import antvUpdateV3ToV4 from '../src/antdv_v3_v4'
program
  .name('my-cli')
  .description('CLI工具')
  .version('1.0')
  .option('--antdv <cwd>', 'antdv v3升级v4工具')
program.parse();
const options = program.opts();
if (options.antdv) {
   
  antvUpdateV3ToV4(options.antdv);
}

在脚本的顶部使用 #!/usr/bin/env node 这一行被称为 “shebang”(或 “hashbang”)。它在类 Unix 操作系统中用于指示应使用哪个解释器来执行该脚本。以下是它的作用的详细解释:

**Shebang (#!):**这是一个字符序列,告诉操作系统该文件应该使用某个解释器来执行。

**/usr/bin/env:**这是一个命令,用于定位并运行指定的解释器。使用 env 是一种常见做法,因为它会搜索用户的 PATH 环境变量来找到解释器,从而使脚本在不同系统上更具可移植性,因为解释器可能安装在不同的位置。

**node:**这指定了脚本应该使用 Node.js 解释器来运行。

2.配置package.json

在这里插入图片描述

读取项目文件,判断文件类型

index.ts

import {
    glob } from 'glob'
import {
    readFile, writeFile, access, mkdir } from 'node:fs/promises'
import {
    extname } from 'node:path'
import * as pathtool from 'path'
import {
    vueParser } from './parser/vue'
import {
    templateTransformer } from './transformer/template'
import {
    javascriptTransformer, JavaScriptCodeType } from './transformer/javascript'
let antdv_v3_v4: {
    [prop: string]: Object[] } = {
   }
let jsRepalceKeysArray: {
    [prop: string]: {
   }[] } = {
   }
let handlePropArray: {
    [prop: string]: {
   }[] } = {
   }
async function vueHandler(content: string, path: string) {
   
  console.log('vueHandlerpath: ', path);
  let resultCode = ''
  let changeArr: boolean[] = []
  const {
    headerComment, template, scriptInfo, otherContent } = vueParser(content)
  // 头部注释
  resultCode += `${
     headerComment}\n`
  // 处理template
  const {
    result: templateResult, handlePropArray: handleProp, hasChange: templateHasChange, jsRepalceKeysArray: jsRepalceKeys } = await templateTransformer(template)
  jsRepalceKeysArray[path] = jsRepalceKeys
  handlePropArray[path] = handleProp
  // resultCode += templateResult
  resultCode += `${
     templateResult}\n`
  changeArr.push(templateHasChange)
  antdv_v3_v4[path] = handleProp

  // 处理script
  for (const item of scriptInfo) {
   
    const codeType = item.type === 'setup' ? JavaScriptCodeType.Vue3Composition : JavaScriptCodeType.Vue2;
    const {
    hasChange, result, } = await javascriptTransformer(item.content, codeType, jsRepalceKeys);
    resultCode += `\n${
     item.head}\n${
     result}\n</script>\n`;
    changeArr.push(hasChange);
  }

  resultCode += `\n${
     otherContent}\n`

  if (changeArr.includes(true)) {
   //文件是否有变更,变更重新写入,没有不做操作
    const filePath = path
    const dir = pathtool.dirname(filePath);
    try {
   //检查目录是否存在
      await access(dir);
    } catch (error) {
   
      await mkdir(dir, {
    recursive: true });
    }
    await writeFile(filePath, resultCode)
  }

}

const main = async (cwd: string) => {
   
  // 获取文件
  const matchFiles = await glob('**/*.{vue,js,ts}', {
   
    cwd,//文件名称(绝对路径)
    absolute: true
  })
  let i = 0
  for (const path of matchFiles) {
   
    if (path.includes('locales')) continue
    // 读取文件内容
    const fileContent = await readFile(path, 'utf-8')
    // 获取后缀
    const ext = extname(path)
    switch (ext) {
   
      case '.vue': {
   
        await vueHandler(fileContent, path)
        break
      }
    }
  }

  // 生成日志
  generateLog(cwd + '/ant3_4.json', handlePropArray, jsRepalceKeysArray)
}
const generateLog = async (cwd, templateObj, jsObj) => {
   
  const result = {
   }
  for (const filePath in templateObj) {
   
    result[filePath] = {
   
      template: templateObj[filePath],
      js: jsObj[filePath]
    }
  }
  await writeFile(cwd, JSON.stringify(result, null, 2))
}


export default main;

分别获取vue文件 template js(vue2和vue3)

parser vue.ts

import {
    parse } from '@vue/compiler-dom'
import type {
    ElementNode } from '@vue/compiler-dom'

function getScriptHead(props) {
   
  let attr: string[] = []
  for (const prop of props) {
   
    let val =  ''
    if (prop.value) {
   
      val = `="${
     prop.value.content}"`
    }
    attr.push(`${
     prop.name}${
     val}`)
  }
  const separator = attr.length === 0 ? '' : ' '
  return `<script${
     separator + attr.join(' ')}>`
}
function extractHeaderComment(content) {
   

  // 使用正则表达式匹配头部注释
  const match = content.match(/<!--[\s\S]*?@Description:[\s\S]*?-->/);

  if (match) {
   
    return match[0];
  } else {
   
    return '';
  }
}

interface ScriptInfo {
   
  type: 'setup' | 'optionapi',
  head: string
  content: string
}

export function vueParser(rawContent: string) {
   
  const result = parse(rawContent)
  let headerComment: string = extractHeaderComment(rawContent)
  let template: string = ''
  let script: string = ''
  let scriptSetup: string = ''
  let otherContent: string = ''
  let scriptHead: string = ''
  const scriptInfo: ScriptInfo[] = []
  result.children.forEach((item) => {
   
    if ((item as ElementNode)?.tag === 'template') {
   
      template = item.loc.source
    } else if (item.type === 1 && item.tag === 'script') {
   
      const tempInfo:ScriptInfo = {
   
        type: 'setup',
        head: getScriptHead(item.props),
        content: ''
      }
      scriptHead = getScriptHead(item.props)
      if ((item as ElementNode)?.props?.some?.((prop) => prop.name === 'setup') || item.loc.source.includes('defineComponent')) {
   
        scriptSetup = (item 

http://www.kler.cn/news/366737.html

相关文章:

  • 鸿蒙开发初级证书考试答案
  • 【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (七):MongoDB的设置
  • 【Linux】线程池详解及其基本架构与单例模式实现
  • unity中的组件(Component)
  • java中常见集合,非常重要!!!
  • 【Java】java 集合框架(详解)
  • git清理本地.git文件夹下的缓存
  • Adobe Media Encoder--将可变帧率视频转为固定帧率
  • 用Python实现中文分词
  • #网络安全#渗透测试# 渗透测试应用
  • centos安装指定版本的jenkins
  • 全WEB端支持H.265,RTSP/RTMP/FLV视频流4k超清播放器方案
  • 三款PDF解密工具,轻松打开加密文档
  • 第11天理解指针
  • Go小技巧易错点100例(十八)
  • [申请] 准备 2024.10.20
  • QT模块--Core
  • Oracle数据库语法的使用
  • envoyFilter导致的webSockets协议无法正常工作
  • Docker Redis集群3主3从模式
  • 网关三问:为什么微服务需要网关?什么是微服务网关?网关怎么选型?
  • 4款免费音频剪辑软件带你开启声音创作之旅
  • 基于SpringBoot的时装购物系统【源码】+【论文】
  • BRIA-RMBG-1.4容器构建指南
  • 2024年最新苹果iOS证书申请创建App详细图文流程
  • Jmeter用户定义变量