Files
wwjcloud-nest-v1/wwjcloud-nest-v1/tools/tools-uni/generators/script-transformer.js
wanwujie 0f105d3a21 🎯 重构目录结构:完成项目组织优化
- 将wwjcloud目录重命名为wwjcloud-nest-v1作为项目根目录
- 将原nestjs目录重命名为wwjcloud作为NestJS后端目录
- 实现真正的前后端分离架构
- 恢复工作区中丢失的目录结构
- 更新相关配置文件路径引用
- 清理重复和嵌套目录问题

目录结构:
wwjcloud-nest-v1/
├── wwjcloud/          # NestJS 后端
├── admin/             # 管理端前端
├── web/               # PC端前端
├── uni-app-x/         # 移动端前端
├── wwjcloud-web/      # 部署根目录
├── docker/            # Docker 配置
├── docs/              # 文档
└── tools/             # 工具集
2025-10-21 13:38:58 +08:00

291 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Script转换器 - TypeScript/JavaScript 到 UTS
* 将uni-app 3.x的脚本代码转换为uni-app x的UTS格式
*/
class ScriptTransformer {
constructor() {
this.transformRules = [
// Vue3 Composition API转换
this.transformVueImports.bind(this),
this.transformReactiveApi.bind(this),
this.transformLifecycleHooks.bind(this),
// TypeScript到UTS转换
this.transformTypeAnnotations.bind(this),
this.transformTsSyntax.bind(this),
// uni-app API转换
this.transformUniApi.bind(this),
// 其他语法转换
this.transformAsyncAwait.bind(this),
this.transformImportExport.bind(this)
];
}
/**
* 转换脚本内容
*/
transform(sourceCode, options = {}) {
let transformedCode = sourceCode;
console.log(' 🔄 开始脚本转换...');
// 应用所有转换规则
for (const rule of this.transformRules) {
try {
transformedCode = rule(transformedCode, options);
} catch (error) {
console.log(` ⚠️ 转换规则执行出错: ${error.message}`);
}
}
// 最终清理
transformedCode = this.finalCleanup(transformedCode);
console.log(' ✅ 脚本转换完成');
return transformedCode;
}
/**
* 转换Vue导入
*/
transformVueImports(code) {
// Vue 3.x导入转换为uni-app x兼容格式
code = code.replace(
/import\s*{\s*([^}]+)\s*}\s*from\s*['"]vue['"];?/g,
(match, imports) => {
// 检查是否包含需要UTS特殊处理的导入
const uniappXImports = imports.split(',').map(imp => imp.trim());
const needsTransform = uniappXImports.some(imp =>
['ref', 'reactive', 'computed', 'watch', 'onMounted', 'onUnmounted'].includes(imp)
);
if (needsTransform) {
return `// UTS兼容导入\nimport { ${imports.trim()} } from 'vue';`;
}
return match;
}
);
return code;
}
/**
* 转换响应式API
*/
transformReactiveApi(code) {
// ref类型声明转换
code = code.replace(
/const\s+(\w+)\s*=\s*ref<([^>]+)>\(([^)]*)\)/g,
'const $1 = ref<$2>($3)'
);
// reactive对象类型转换
code = code.replace(
/const\s+(\w+)\s*=\s*reactive<([^>]+)>\(/g,
'const $1 = reactive<$2>('
);
return code;
}
/**
* 转换生命周期钩子
*/
transformLifecycleHooks(code) {
// uni-app特有生命周期保持Vue标准生命周期适配
const lifecycleMap = {
'onMounted': 'onMounted',
'onUnmounted': 'onUnmounted',
'onUpdated': 'onUpdated',
'onBeforeMount': 'onBeforeMount',
'onBeforeUnmount': 'onBeforeUnmount',
'onBeforeUpdate': 'onBeforeUpdate'
};
// 确保生命周期钩子的UTS兼容性
for (const [vueHook, utsHook] of Object.entries(lifecycleMap)) {
if (code.includes(vueHook)) {
code = code.replace(
new RegExp(`\\b${vueHook}\\b`, 'g'),
utsHook
);
}
}
return code;
}
/**
* 转换类型注解
*/
transformTypeAnnotations(code) {
// TypeScript接口转UTS类型定义
code = code.replace(
/interface\s+(\w+)\s*{([^}]+)}/g,
(match, name, content) => {
return `interface ${name} {\n${this.convertInterfaceContent(content)}\n}`;
}
);
// 函数参数类型转换
code = code.replace(
/(\w+)\s*:\s*Array<([^>]+)>/g,
'$1: $2[]'
);
// any类型转换UTS中尽量避免any
code = code.replace(/\bany\b/g, 'unknown');
return code;
}
/**
* 转换TypeScript特定语法
*/
transformTsSyntax(code) {
// 移除可选参数中的?UTS处理方式不同
code = code.replace(/(\w+)\?/g, '$1 | null');
// 泛型约束调整
code = code.replace(/<T\s+extends\s+([^>]+)>/g, '<T: $1>');
// 类型断言转换
code = code.replace(/as\s+([A-Za-z_][A-Za-z0-9_]*)/g, 'as $1');
return code;
}
/**
* 转换uni-app API调用
*/
transformUniApi(code) {
// uni.* API调用保持但确保UTS兼容
// 大部分uni API在uni-app x中保持不变
// 处理可能需要调整的API
const apiAdjustments = {
'uni.request': 'uni.request', // 保持
'uni.showModal': 'uni.showModal', // 保持
'uni.showToast': 'uni.showToast', // 保持
'uni.navigateTo': 'uni.navigateTo', // 保持
'uni.getSystemInfo': 'uni.getSystemInfo' // 保持
};
// 检查是否使用了不兼容的API
if (code.includes('uni.createCanvasContext')) {
console.log(' ⚠️ 检测到可能不兼容的API: uni.createCanvasContext');
}
return code;
}
/**
* 转换异步语法
*/
transformAsyncAwait(code) {
// Promise类型声明转换
code = code.replace(
/Promise<([^>]+)>/g,
'Promise<$1>'
);
// async/await保持但确保返回类型正确
code = code.replace(
/async\s+(\w+)\s*\([^)]*\)\s*:\s*Promise<([^>]+)>/g,
'async $1(...args: any[]): Promise<$2>'
);
return code;
}
/**
* 转换导入导出
*/
transformImportExport(code) {
// 导入路径调整(如果需要)
code = code.replace(
/from\s+['"]@\/([^'"]+)['"]/g,
"from '@/$1'"
);
// 确保导出语法UTS兼容
code = code.replace(
/export\s+default\s+\{/g,
'export default {'
);
return code;
}
/**
* 转换接口内容
*/
convertInterfaceContent(content) {
return content
.split('\n')
.map(line => {
// 移除行尾分号UTS可选
line = line.replace(/;(\s*)$/, '$1');
return line;
})
.join('\n');
}
/**
* 最终清理
*/
finalCleanup(code) {
// 移除多余空行
code = code.replace(/\n{3,}/g, '\n\n');
// 确保正确的缩进
const lines = code.split('\n');
let indentLevel = 0;
return lines.map(line => {
const trimmed = line.trim();
if (trimmed === '') return '';
// 减少缩进级别
if (trimmed.startsWith('}') || trimmed.startsWith(']') || trimmed.startsWith(')')) {
indentLevel = Math.max(0, indentLevel - 1);
}
const indent = ' '.repeat(indentLevel);
const result = indent + trimmed;
// 增加缩进级别
if (trimmed.endsWith('{') || trimmed.endsWith('[') || trimmed.endsWith('(')) {
indentLevel++;
}
return result;
}).join('\n');
}
/**
* 验证转换后的代码
*/
validateTransformedCode(code) {
const issues = [];
// 检查是否还有TypeScript特有语法
if (code.includes('<T extends')) {
issues.push('发现泛型约束,可能需要调整');
}
if (code.includes('!:')) {
issues.push('发现非空断言UTS中需要调整');
}
return issues;
}
}
module.exports = ScriptTransformer;