diff --git a/web-front/package.json b/web-front/package.json index b26be00..1881029 100644 --- a/web-front/package.json +++ b/web-front/package.json @@ -19,6 +19,7 @@ "monaco-editor": "^0.45.0", "qrcode": "^1.5.4", "splitpanes": "^4.0.4", + "typescript": "^5.9.3", "vue": "^3.5.12", "vue-clipboard3": "^2.0.0", "vue-router": "^4.5.1", diff --git a/web-front/src/utils/playgroundApi.js b/web-front/src/utils/playgroundApi.js index 91fabe0..d65854d 100644 --- a/web-front/src/utils/playgroundApi.js +++ b/web-front/src/utils/playgroundApi.js @@ -141,6 +141,56 @@ export const playgroundApi = { } catch (error) { throw new Error(error.response?.data?.error || error.response?.data?.msg || error.message || '获取解析器失败'); } + }, + + /** + * 保存TypeScript代码及其编译结果 + */ + async saveTypeScriptCode(parserId, tsCode, es5Code, compileErrors, compilerVersion, compileOptions, isValid) { + try { + const response = await axios.post('/v2/playground/typescript', { + parserId, + tsCode, + es5Code, + compileErrors, + compilerVersion, + compileOptions, + isValid + }); + return response.data; + } catch (error) { + throw new Error(error.response?.data?.error || error.response?.data?.msg || error.message || '保存TypeScript代码失败'); + } + }, + + /** + * 根据parserId获取TypeScript代码 + */ + async getTypeScriptCode(parserId) { + try { + const response = await axios.get(`/v2/playground/typescript/${parserId}`); + return response.data; + } catch (error) { + throw new Error(error.response?.data?.error || error.response?.data?.msg || error.message || '获取TypeScript代码失败'); + } + }, + + /** + * 更新TypeScript代码 + */ + async updateTypeScriptCode(parserId, tsCode, es5Code, compileErrors, compilerVersion, compileOptions, isValid) { + try { + const response = await axios.put(`/v2/playground/typescript/${parserId}`, { + tsCode, + es5Code, + compileErrors, + compilerVersion, + compileOptions, + isValid + }); + return response.data; + } catch (error) { + throw new Error(error.response?.data?.error || error.response?.data?.msg || error.message || '更新TypeScript代码失败'); + } } }; - diff --git a/web-front/src/utils/tsCompiler.js b/web-front/src/utils/tsCompiler.js new file mode 100644 index 0000000..bc2c2a4 --- /dev/null +++ b/web-front/src/utils/tsCompiler.js @@ -0,0 +1,167 @@ +import * as ts from 'typescript'; + +/** + * TypeScript编译器工具类 + * 用于在浏览器中将TypeScript代码编译为ES5 JavaScript + */ + +/** + * 编译TypeScript代码为ES5 JavaScript + * @param {string} sourceCode - TypeScript源代码 + * @param {string} fileName - 文件名(默认为script.ts) + * @returns {Object} 编译结果 { success: boolean, code: string, errors: Array } + */ +export function compileToES5(sourceCode, fileName = 'script.ts') { + try { + // 编译选项 + const compilerOptions = { + target: ts.ScriptTarget.ES5, // 目标版本:ES5 + module: ts.ModuleKind.None, // 不使用模块系统 + lib: ['lib.es5.d.ts', 'lib.dom.d.ts'], // 包含ES5和DOM类型定义 + removeComments: false, // 保留注释 + noEmitOnError: false, // 即使有错误也生成代码 + noImplicitAny: false, // 允许隐式any类型 + strictNullChecks: false, // 不进行严格的null检查 + suppressImplicitAnyIndexErrors: true, // 抑制隐式any索引错误 + downlevelIteration: true, // 支持ES5迭代器降级 + esModuleInterop: true, // 启用ES模块互操作性 + allowJs: true, // 允许编译JavaScript文件 + checkJs: false // 不检查JavaScript文件 + }; + + // 执行编译 + const result = ts.transpileModule(sourceCode, { + compilerOptions, + fileName, + reportDiagnostics: true + }); + + // 检查是否有诊断信息(错误/警告) + const diagnostics = result.diagnostics || []; + const errors = diagnostics.map(diagnostic => { + const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); + let location = ''; + if (diagnostic.file && diagnostic.start !== undefined) { + const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); + location = `(${line + 1},${character + 1})`; + } + return { + message, + location, + category: ts.DiagnosticCategory[diagnostic.category], + code: diagnostic.code + }; + }); + + // 过滤出真正的错误(不包括警告) + const realErrors = errors.filter(e => e.category === 'Error'); + + return { + success: realErrors.length === 0, + code: result.outputText || '', + errors: errors, + hasWarnings: errors.some(e => e.category === 'Warning'), + sourceMap: result.sourceMapText + }; + } catch (error) { + return { + success: false, + code: '', + errors: [{ + message: error.message || '编译失败', + location: '', + category: 'Error', + code: 0 + }] + }; + } +} + +/** + * 检查代码是否为TypeScript代码 + * 简单的启发式检查,看是否包含TypeScript特有的语法 + * @param {string} code - 代码字符串 + * @returns {boolean} 是否为TypeScript代码 + */ +export function isTypeScriptCode(code) { + if (!code || typeof code !== 'string') { + return false; + } + + // TypeScript特有的语法模式 + const tsPatterns = [ + /:\s*(string|number|boolean|any|void|never|unknown|object)\b/, // 类型注解 + /interface\s+\w+/, // interface声明 + /type\s+\w+\s*=/, // type别名 + /enum\s+\w+/, // enum声明 + /<\w+>/, // 泛型 + /implements\s+\w+/, // implements关键字 + /as\s+(string|number|boolean|any|const)/, // as类型断言 + /public|private|protected|readonly/, // 访问修饰符 + /:\s*\w+\[\]/, // 数组类型注解 + /\?\s*:/ // 可选属性 + ]; + + // 如果匹配任何TypeScript特有模式,则认为是TypeScript代码 + return tsPatterns.some(pattern => pattern.test(code)); +} + +/** + * 格式化编译错误信息 + * @param {Array} errors - 错误数组 + * @returns {string} 格式化后的错误信息 + */ +export function formatCompileErrors(errors) { + if (!errors || errors.length === 0) { + return ''; + } + + return errors.map((error, index) => { + const prefix = `[${error.category}]`; + const location = error.location ? ` ${error.location}` : ''; + const code = error.code ? ` (TS${error.code})` : ''; + return `${index + 1}. ${prefix}${location}${code}: ${error.message}`; + }).join('\n'); +} + +/** + * 验证编译后的代码是否为有效的ES5 + * @param {string} code - 编译后的代码 + * @returns {Object} { valid: boolean, error: string } + */ +export function validateES5Code(code) { + try { + // 尝试使用Function构造函数验证语法 + // eslint-disable-next-line no-new-func + new Function(code); + return { valid: true, error: null }; + } catch (error) { + return { valid: false, error: error.message }; + } +} + +/** + * 提取代码中的元数据注释 + * @param {string} code - 代码字符串 + * @returns {Object} 元数据对象 + */ +export function extractMetadata(code) { + const metadata = {}; + const metaRegex = /\/\/\s*@(\w+)\s+(.+)/g; + let match; + + while ((match = metaRegex.exec(code)) !== null) { + const [, key, value] = match; + metadata[key] = value.trim(); + } + + return metadata; +} + +export default { + compileToES5, + isTypeScriptCode, + formatCompileErrors, + validateES5Code, + extractMetadata +}; diff --git a/web-front/src/views/Playground.vue b/web-front/src/views/Playground.vue index c61cfba..bf8594c 100644 --- a/web-front/src/views/Playground.vue +++ b/web-front/src/views/Playground.vue @@ -5,6 +5,11 @@
JS解析器演练场 + + + JavaScript + TypeScript +
@@ -479,6 +484,7 @@ import 'splitpanes/dist/splitpanes.css'; import MonacoEditor from '@/components/MonacoEditor.vue'; import { playgroundApi } from '@/utils/playgroundApi'; import { configureMonacoTypes, loadTypesFromApi } from '@/utils/monacoTypes'; +import { compileToES5, isTypeScriptCode, formatCompileErrors } from '@/utils/tsCompiler'; import JsonViewer from 'vue3-json-viewer'; export default { @@ -492,6 +498,9 @@ export default { setup() { const editorRef = ref(null); const jsCode = ref(''); + const codeLanguage = ref('JavaScript'); // 新增:代码语言选择 + const compiledES5Code = ref(''); // 新增:编译后的ES5代码 + const compileStatus = ref({ success: true, errors: [] }); // 新增:编译状态 const testParams = ref({ shareUrl: 'https://lanzoui.com/i7Aq12ab3cd', pwd: '', @@ -699,6 +708,62 @@ function parseById(shareLinkInfo, http, logger) { const clearCode = () => { jsCode.value = ''; testResult.value = null; + compiledES5Code.value = ''; + compileStatus.value = { success: true, errors: [] }; + }; + + // 语言切换处理 + const onLanguageChange = (newLanguage) => { + console.log('切换语言:', newLanguage); + // 保存当前语言选择 + localStorage.setItem('playground_language', newLanguage); + + // 如果切换到TypeScript,尝试编译当前代码 + if (newLanguage === 'TypeScript' && jsCode.value.trim()) { + compileTypeScriptCode(); + } + }; + + // 编译TypeScript代码 + const compileTypeScriptCode = () => { + if (!jsCode.value.trim()) { + compiledES5Code.value = ''; + compileStatus.value = { success: true, errors: [] }; + return; + } + + try { + const result = compileToES5(jsCode.value); + compiledES5Code.value = result.code; + compileStatus.value = { + success: result.success, + errors: result.errors || [], + hasWarnings: result.hasWarnings + }; + + if (!result.success) { + const errorMsg = formatCompileErrors(result.errors); + ElMessage.error({ + message: '编译失败,请检查代码语法\n' + errorMsg, + duration: 5000, + showClose: true + }); + } else if (result.hasWarnings) { + ElMessage.warning({ + message: '编译成功,但存在警告', + duration: 3000 + }); + } else { + ElMessage.success('编译成功'); + } + } catch (error) { + console.error('编译错误:', error); + compileStatus.value = { + success: false, + errors: [{ message: error.message || '编译失败' }] + }; + ElMessage.error('编译失败: ' + error.message); + } }; // 执行测试 @@ -744,9 +809,60 @@ function parseById(shareLinkInfo, http, logger) { testResult.value = null; consoleLogs.value = []; // 清空控制台 + // 确定要执行的代码(TypeScript需要先编译) + let codeToExecute = jsCode.value; + + // 如果是TypeScript模式或代码看起来像TypeScript,先编译 + if (codeLanguage.value === 'TypeScript' || isTypeScriptCode(jsCode.value)) { + try { + const compileResult = compileToES5(jsCode.value); + + if (!compileResult.success) { + testing.value = false; + const errorMsg = formatCompileErrors(compileResult.errors); + ElMessage.error({ + message: 'TypeScript编译失败,请修复错误后再试\n' + errorMsg, + duration: 5000, + showClose: true + }); + testResult.value = { + success: false, + error: 'TypeScript编译失败', + stackTrace: errorMsg, + logs: [], + executionTime: 0 + }; + return; + } + + // 使用编译后的ES5代码 + codeToExecute = compileResult.code; + compiledES5Code.value = compileResult.code; + compileStatus.value = { + success: true, + errors: compileResult.errors || [], + hasWarnings: compileResult.hasWarnings + }; + + if (compileResult.hasWarnings) { + ElMessage.warning('编译成功,但存在警告'); + } + } catch (error) { + testing.value = false; + ElMessage.error('TypeScript编译失败: ' + error.message); + testResult.value = { + success: false, + error: 'TypeScript编译失败: ' + error.message, + logs: [], + executionTime: 0 + }; + return; + } + } + try { const result = await playgroundApi.testScript( - jsCode.value, + codeToExecute, // 使用编译后的代码或原始JS代码 testParams.value.shareUrl, testParams.value.pwd, testParams.value.method @@ -1196,6 +1312,12 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}" } } + // 加载保存的语言选择 + const savedLanguage = localStorage.getItem('playground_language'); + if (savedLanguage) { + codeLanguage.value = savedLanguage; + } + // 监听主题变化 if (document.documentElement) { const observer = new MutationObserver(() => { @@ -1214,6 +1336,9 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}" return { editorRef, jsCode, + codeLanguage, + compiledES5Code, + compileStatus, testParams, testResult, testing, @@ -1221,6 +1346,8 @@ curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}" editorTheme, editorOptions, onCodeChange, + onLanguageChange, + compileTypeScriptCode, loadTemplate, formatCode, saveCode, diff --git a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java index bc5e4bc..e14fee8 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/controller/PlaygroundApi.java @@ -422,6 +422,132 @@ public class PlaygroundApi { return dbService.getPlaygroundParserById(id); } + /** + * 保存TypeScript代码及其编译结果 + */ + @RouteMapping(value = "/typescript", method = RouteMethod.POST) + public Future saveTypeScriptCode(RoutingContext ctx) { + Promise promise = Promise.promise(); + + try { + JsonObject body = ctx.body().asJsonObject(); + Long parserId = body.getLong("parserId"); + String tsCode = body.getString("tsCode"); + String es5Code = body.getString("es5Code"); + String compileErrors = body.getString("compileErrors"); + String compilerVersion = body.getString("compilerVersion"); + String compileOptions = body.getString("compileOptions"); + Boolean isValid = body.getBoolean("isValid", true); + + if (parserId == null) { + promise.complete(JsonResult.error("解析器ID不能为空").toJsonObject()); + return promise.future(); + } + + if (StringUtils.isBlank(tsCode)) { + promise.complete(JsonResult.error("TypeScript代码不能为空").toJsonObject()); + return promise.future(); + } + + if (StringUtils.isBlank(es5Code)) { + promise.complete(JsonResult.error("编译后的ES5代码不能为空").toJsonObject()); + return promise.future(); + } + + // 代码长度验证 + if (tsCode.length() > MAX_CODE_LENGTH || es5Code.length() > MAX_CODE_LENGTH) { + promise.complete(JsonResult.error("代码长度超过限制(最大128KB)").toJsonObject()); + return promise.future(); + } + + JsonObject tsCodeInfo = new JsonObject(); + tsCodeInfo.put("parserId", parserId); + tsCodeInfo.put("tsCode", tsCode); + tsCodeInfo.put("es5Code", es5Code); + tsCodeInfo.put("compileErrors", compileErrors); + tsCodeInfo.put("compilerVersion", compilerVersion); + tsCodeInfo.put("compileOptions", compileOptions); + tsCodeInfo.put("isValid", isValid); + tsCodeInfo.put("ip", getClientIp(ctx.request())); + + dbService.saveTypeScriptCode(tsCodeInfo).onSuccess(result -> { + promise.complete(result); + }).onFailure(e -> { + log.error("保存TypeScript代码失败", e); + promise.complete(JsonResult.error("保存失败: " + e.getMessage()).toJsonObject()); + }); + + } catch (Exception e) { + log.error("解析请求参数失败", e); + promise.complete(JsonResult.error("解析请求参数失败: " + e.getMessage()).toJsonObject()); + } + + return promise.future(); + } + + /** + * 根据parserId获取TypeScript代码 + */ + @RouteMapping(value = "/typescript/:parserId", method = RouteMethod.GET) + public Future getTypeScriptCode(Long parserId) { + return dbService.getTypeScriptCodeByParserId(parserId); + } + + /** + * 更新TypeScript代码 + */ + @RouteMapping(value = "/typescript/:parserId", method = RouteMethod.PUT) + public Future updateTypeScriptCode(RoutingContext ctx, Long parserId) { + Promise promise = Promise.promise(); + + try { + JsonObject body = ctx.body().asJsonObject(); + String tsCode = body.getString("tsCode"); + String es5Code = body.getString("es5Code"); + String compileErrors = body.getString("compileErrors"); + String compilerVersion = body.getString("compilerVersion"); + String compileOptions = body.getString("compileOptions"); + Boolean isValid = body.getBoolean("isValid", true); + + if (StringUtils.isBlank(tsCode)) { + promise.complete(JsonResult.error("TypeScript代码不能为空").toJsonObject()); + return promise.future(); + } + + if (StringUtils.isBlank(es5Code)) { + promise.complete(JsonResult.error("编译后的ES5代码不能为空").toJsonObject()); + return promise.future(); + } + + // 代码长度验证 + if (tsCode.length() > MAX_CODE_LENGTH || es5Code.length() > MAX_CODE_LENGTH) { + promise.complete(JsonResult.error("代码长度超过限制(最大128KB)").toJsonObject()); + return promise.future(); + } + + JsonObject tsCodeInfo = new JsonObject(); + tsCodeInfo.put("tsCode", tsCode); + tsCodeInfo.put("es5Code", es5Code); + tsCodeInfo.put("compileErrors", compileErrors); + tsCodeInfo.put("compilerVersion", compilerVersion); + tsCodeInfo.put("compileOptions", compileOptions); + tsCodeInfo.put("isValid", isValid); + + dbService.updateTypeScriptCode(parserId, tsCodeInfo).onSuccess(result -> { + promise.complete(result); + }).onFailure(e -> { + log.error("更新TypeScript代码失败", e); + promise.complete(JsonResult.error("更新失败: " + e.getMessage()).toJsonObject()); + }); + + } catch (Exception e) { + log.error("解析请求参数失败", e); + promise.complete(JsonResult.error("解析请求参数失败: " + e.getMessage()).toJsonObject()); + } + + return promise.future(); + } + /** * 获取客户端IP */ diff --git a/web-service/src/main/java/cn/qaiu/lz/web/model/PlaygroundTypeScriptCode.java b/web-service/src/main/java/cn/qaiu/lz/web/model/PlaygroundTypeScriptCode.java new file mode 100644 index 0000000..43af4ad --- /dev/null +++ b/web-service/src/main/java/cn/qaiu/lz/web/model/PlaygroundTypeScriptCode.java @@ -0,0 +1,55 @@ +package cn.qaiu.lz.web.model; + +import cn.qaiu.db.ddl.Constraint; +import cn.qaiu.db.ddl.Length; +import cn.qaiu.db.ddl.Table; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.util.Date; + +/** + * 演练场TypeScript代码实体 + * 用于保存用户编写的TypeScript源代码 + * 与PlaygroundParser关联,存储原始TS代码和编译后的ES5代码 + */ +@Data +@Table("playground_typescript_code") +public class PlaygroundTypeScriptCode { + + private static final long serialVersionUID = 1L; + + @Constraint(autoIncrement = true, notNull = true) + private Long id; + + @Constraint(notNull = true) + private Long parserId; // 关联的解析器ID(外键) + + @Length(varcharSize = 65535) + @Constraint(notNull = true) + private String tsCode; // TypeScript原始代码 + + @Length(varcharSize = 65535) + @Constraint(notNull = true) + private String es5Code; // 编译后的ES5代码 + + @Length(varcharSize = 2000) + private String compileErrors; // 编译错误信息(如果有) + + @Length(varcharSize = 32) + private String compilerVersion; // 编译器版本 + + @Length(varcharSize = 1000) + private String compileOptions; // 编译选项(JSON格式) + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime = new Date(); // 创建时间 + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; // 更新时间 + + private Boolean isValid = true; // 编译是否成功 + + @Length(varcharSize = 64) + private String ip; // 创建者IP +} diff --git a/web-service/src/main/java/cn/qaiu/lz/web/service/DbService.java b/web-service/src/main/java/cn/qaiu/lz/web/service/DbService.java index 0256d2e..7c8716e 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/service/DbService.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/service/DbService.java @@ -50,4 +50,19 @@ public interface DbService extends BaseAsyncService { */ Future getPlaygroundParserById(Long id); + /** + * 保存TypeScript代码及其编译结果 + */ + Future saveTypeScriptCode(JsonObject tsCodeInfo); + + /** + * 根据parserId获取TypeScript代码 + */ + Future getTypeScriptCodeByParserId(Long parserId); + + /** + * 更新TypeScript代码 + */ + Future updateTypeScriptCode(Long parserId, JsonObject tsCodeInfo); + } diff --git a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java index 87aa228..845abb8 100644 --- a/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java +++ b/web-service/src/main/java/cn/qaiu/lz/web/service/impl/DbServiceImpl.java @@ -265,4 +265,114 @@ public class DbServiceImpl implements DbService { return promise.future(); } + + @Override + public Future saveTypeScriptCode(JsonObject tsCodeInfo) { + JDBCPool client = JDBCPoolInit.instance().getPool(); + Promise promise = Promise.promise(); + + String sql = """ + INSERT INTO playground_typescript_code + (parser_id, ts_code, es5_code, compile_errors, compiler_version, + compile_options, create_time, is_valid, ip) + VALUES (?, ?, ?, ?, ?, ?, NOW(), ?, ?) + """; + + client.preparedQuery(sql) + .execute(Tuple.of( + tsCodeInfo.getLong("parserId"), + tsCodeInfo.getString("tsCode"), + tsCodeInfo.getString("es5Code"), + tsCodeInfo.getString("compileErrors"), + tsCodeInfo.getString("compilerVersion"), + tsCodeInfo.getString("compileOptions"), + tsCodeInfo.getBoolean("isValid", true), + tsCodeInfo.getString("ip") + )) + .onSuccess(res -> { + promise.complete(JsonResult.success("保存TypeScript代码成功").toJsonObject()); + }) + .onFailure(e -> { + log.error("saveTypeScriptCode failed", e); + promise.fail(e); + }); + + return promise.future(); + } + + @Override + public Future getTypeScriptCodeByParserId(Long parserId) { + JDBCPool client = JDBCPoolInit.instance().getPool(); + Promise promise = Promise.promise(); + + String sql = "SELECT * FROM playground_typescript_code WHERE parser_id = ? ORDER BY create_time DESC LIMIT 1"; + + client.preparedQuery(sql) + .execute(Tuple.of(parserId)) + .onSuccess(rows -> { + if (rows.size() > 0) { + Row row = rows.iterator().next(); + JsonObject tsCode = new JsonObject(); + tsCode.put("id", row.getLong("id")); + tsCode.put("parserId", row.getLong("parser_id")); + tsCode.put("tsCode", row.getString("ts_code")); + tsCode.put("es5Code", row.getString("es5_code")); + tsCode.put("compileErrors", row.getString("compile_errors")); + tsCode.put("compilerVersion", row.getString("compiler_version")); + tsCode.put("compileOptions", row.getString("compile_options")); + var createTime = row.getLocalDateTime("create_time"); + if (createTime != null) { + tsCode.put("createTime", createTime.toString().replace("T", " ")); + } + var updateTime = row.getLocalDateTime("update_time"); + if (updateTime != null) { + tsCode.put("updateTime", updateTime.toString().replace("T", " ")); + } + tsCode.put("isValid", row.getBoolean("is_valid")); + tsCode.put("ip", row.getString("ip")); + promise.complete(JsonResult.data(tsCode).toJsonObject()); + } else { + promise.complete(JsonResult.data(null).toJsonObject()); + } + }) + .onFailure(e -> { + log.error("getTypeScriptCodeByParserId failed", e); + promise.fail(e); + }); + + return promise.future(); + } + + @Override + public Future updateTypeScriptCode(Long parserId, JsonObject tsCodeInfo) { + JDBCPool client = JDBCPoolInit.instance().getPool(); + Promise promise = Promise.promise(); + + String sql = """ + UPDATE playground_typescript_code + SET ts_code = ?, es5_code = ?, compile_errors = ?, compiler_version = ?, + compile_options = ?, update_time = NOW(), is_valid = ? + WHERE parser_id = ? + """; + + client.preparedQuery(sql) + .execute(Tuple.of( + tsCodeInfo.getString("tsCode"), + tsCodeInfo.getString("es5Code"), + tsCodeInfo.getString("compileErrors"), + tsCodeInfo.getString("compilerVersion"), + tsCodeInfo.getString("compileOptions"), + tsCodeInfo.getBoolean("isValid", true), + parserId + )) + .onSuccess(res -> { + promise.complete(JsonResult.success("更新TypeScript代码成功").toJsonObject()); + }) + .onFailure(e -> { + log.error("updateTypeScriptCode failed", e); + promise.fail(e); + }); + + return promise.future(); + } }