- 将wwjcloud目录重命名为wwjcloud-nest-v1作为项目根目录 - 将原nestjs目录重命名为wwjcloud作为NestJS后端目录 - 实现真正的前后端分离架构 - 恢复工作区中丢失的目录结构 - 更新相关配置文件路径引用 - 清理重复和嵌套目录问题 目录结构: wwjcloud-nest-v1/ ├── wwjcloud/ # NestJS 后端 ├── admin/ # 管理端前端 ├── web/ # PC端前端 ├── uni-app-x/ # 移动端前端 ├── wwjcloud-web/ # 部署根目录 ├── docker/ # Docker 配置 ├── docs/ # 文档 └── tools/ # 工具集
291 lines
8.1 KiB
JavaScript
291 lines
8.1 KiB
JavaScript
#!/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;
|