From 53520dd4d693f4e9bd671887c4c9adadd828ad41 Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Tue, 26 Aug 2025 18:47:56 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat=20(language):=20=E6=94=AF=E6=8C=81=20T?= =?UTF-8?q?ypeScript=20By=20Node.js=20=E5=BC=95=E6=93=8E=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + public/icons/typescript-nodejs.svg | 7 + src-tauri/src/examples/typescript-nodejs.ts | 216 ++++++++++++++++++++ src-tauri/src/plugins/javascript_nodejs.rs | 4 +- src-tauri/src/plugins/manager.rs | 9 +- src-tauri/src/plugins/mod.rs | 1 + src-tauri/src/plugins/typescript_nodejs.rs | 52 +++++ src/composables/useCodeMirrorEditor.ts | 2 + 8 files changed, 288 insertions(+), 4 deletions(-) create mode 100644 public/icons/typescript-nodejs.svg create mode 100644 src-tauri/src/examples/typescript-nodejs.ts create mode 100644 src-tauri/src/plugins/typescript_nodejs.rs diff --git a/README.md b/README.md index 016e451..3160a07 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发 - **Rust** - **Shell** - **Swift** +- **TypeScript (Node.js)** ## 安装 diff --git a/public/icons/typescript-nodejs.svg b/public/icons/typescript-nodejs.svg new file mode 100644 index 0000000..cea945e --- /dev/null +++ b/public/icons/typescript-nodejs.svg @@ -0,0 +1,7 @@ + + + + + Node.js + + \ No newline at end of file diff --git a/src-tauri/src/examples/typescript-nodejs.ts b/src-tauri/src/examples/typescript-nodejs.ts new file mode 100644 index 0000000..b87a761 --- /dev/null +++ b/src-tauri/src/examples/typescript-nodejs.ts @@ -0,0 +1,216 @@ +// JavaScript 示例代码 - CodeForge 代码执行环境 + +function greetUser(name) { + return `Hello, ${name}! 👋`; +} + +// 函数定义 +function addNumbers(a, b) { + return { + result: a + b, + operation: 'addition' + }; +} + +function printArray(arr, label) { + console.log(`${label}: ${arr.join(' ')}`); +} + +function fibonacci(n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} + +// 枚举模拟 +const Weekday = { + MONDAY: 1, + TUESDAY: 2, + WEDNESDAY: 3, + THURSDAY: 4, + FRIDAY: 5, + SATURDAY: 6, + SUNDAY: 7 +}; + +// 主函数 +function main() { + console.log("🎉 欢迎使用 CodeForge!"); + console.log("Welcome to CodeForge!"); + console.log(""); + + console.log("========================================="); + console.log(" CodeForge JavaScript "); + console.log("========================================="); + console.log(""); + + // 基本输出示例 + console.log("✅ JavaScript 运行成功! (JavaScript is working!)"); + console.log("⚡ 这是 JavaScript 程序 (This is JavaScript program)"); + console.log(""); + + // 变量操作 + const name = "CodeForge"; + const version = "JavaScript"; + const number1 = 10; + const number2 = 20; + const calculation = addNumbers(number1, number2); + + console.log("🔢 简单计算 (Simple calculation):"); + console.log(`${number1} + ${number2} = ${calculation.result}`); + console.log(""); + + // 字符串操作 + console.log("📝 字符串操作 (String operations):"); + console.log(`平台名称 (Platform): ${name}`); + console.log(`语言版本 (Language): ${version}`); + console.log(`完整信息 (Full info): ${name} - ${version}`); + console.log(""); + + // 循环示例 + console.log("🔄 循环输出 (Loop output):"); + for (let i = 1; i <= 5; i++) { + console.log(`第 ${i} 次输出 (Output #${i}): Hello from CodeForge!`); + } + console.log(""); + + // 数组操作 + console.log("🍎 数组示例 (Array example):"); + const fruits = ["苹果", "香蕉", "橙子", "葡萄"]; + fruits.forEach((fruit, index) => { + console.log(`${index + 1}. ${fruit}`); + }); + console.log(""); + + // 条件判断 + const score = 85; + console.log("📊 成绩评估 (Score evaluation):"); + if (score >= 90) { + console.log("优秀! (Excellent!)"); + } else if (score >= 80) { + console.log("良好! (Good!)"); + } else if (score >= 60) { + console.log("及格 (Pass)"); + } else { + console.log("需要努力 (Need improvement)"); + } + console.log(""); + + // 对象示例 + console.log("👤 对象示例 (Object example):"); + const person = { + name: "张三", + age: 25, + height: 175.5 + }; + + console.log(`姓名: ${person.name}, 年龄: ${person.age}, 身高: ${person.height} cm`); + console.log(""); + + // 函数示例 + console.log("🎭 函数示例 (Function example):"); + console.log(greetUser("CodeForge用户")); + console.log(""); + + // 数组方法示例 + console.log("💾 数组方法示例 (Array methods example):"); + const dynamicArray = Array.from({ length: 5 }, (_, i) => (i + 1) * 10); + printArray(dynamicArray, "动态数组"); + + // Map 和 Filter 示例 + const squares = dynamicArray.map(x => x * x); + const evenNumbers = dynamicArray.filter(x => x % 20 === 0); + printArray(squares, "平方数"); + printArray(evenNumbers, "能被20整除的数"); + console.log(""); + + // 解构赋值示例 + console.log("🔍 解构赋值示例 (Destructuring example):"); + const [first, second, ...rest] = fruits; + console.log(`第一个水果: ${first}`); + console.log(`第二个水果: ${second}`); + console.log(`其余水果: ${rest.join(', ')}`); + + const { name: personName, age } = person; + console.log(`通过解构获取: ${personName}, ${age}岁`); + console.log(""); + + // 递归示例 + console.log("🔄 递归示例 (Recursion example):"); + const fibN = 7; + const fibResult = fibonacci(fibN); + console.log(`斐波那契数列第${fibN}项: ${fibResult}`); + console.log(""); + + // 数学库示例 + console.log("📐 数学库示例 (Math library example):"); + const angle = 45.0; + const radians = (angle * Math.PI) / 180.0; + console.log(`sin(${angle}°) = ${Math.sin(radians).toFixed(4)}`); + console.log(`cos(${angle}°) = ${Math.cos(radians).toFixed(4)}`); + console.log(`sqrt(16) = ${Math.sqrt(16).toFixed(2)}`); + console.log(""); + + // 位操作示例 + console.log("🔧 位操作示例 (Bitwise operations):"); + const a = 12; // 1100 in binary + const b = 10; // 1010 in binary + console.log(`${a} & ${b} = ${a & b} (AND)`); + console.log(`${a} | ${b} = ${a | b} (OR)`); + console.log(`${a} ^ ${b} = ${a ^ b} (XOR)`); + console.log(`~${a} = ${~a} (NOT)`); + console.log(""); + + // 枚举示例 + console.log("📋 枚举示例 (Enum example):"); + const today = Weekday.WEDNESDAY; + console.log(`今天是星期${today}`); + console.log(""); + + // Promise 和 async/await 示例 + console.log("⚡ 异步示例 (Async example):"); + const asyncExample = async () => { + return new Promise((resolve) => { + setTimeout(() => resolve("异步操作完成!"), 100); + }); + }; + + asyncExample().then((message) => { + console.log(message); + console.log(""); + + // 类示例 + console.log("🎯 类示例 (Class example):"); + class Calculator { + constructor() { + this.history = []; + } + + add(a, b) { + const result = a + b; + this.history.push(`${a} + ${b} = ${result}`); + return result; + } + + getHistory() { + return [...this.history]; + } + } + + const calc = new Calculator(); + calc.add(5, 3); + calc.add(10, 7); + console.log("计算历史:", calc.getHistory()); + console.log(""); + + console.log("🎯 CodeForge JavaScript 代码执行完成!"); + console.log("🎯 CodeForge JavaScript execution completed!"); + console.log(""); + console.log("感谢使用 CodeForge 代码执行环境! 🚀"); + console.log("Thank you for using CodeForge! 🚀"); + }); +} + +// 运行主函数 +main(); \ No newline at end of file diff --git a/src-tauri/src/plugins/javascript_nodejs.rs b/src-tauri/src/plugins/javascript_nodejs.rs index 3c01d5e..8f398fb 100644 --- a/src-tauri/src/plugins/javascript_nodejs.rs +++ b/src-tauri/src/plugins/javascript_nodejs.rs @@ -1,9 +1,9 @@ use super::{LanguagePlugin, PluginConfig}; use std::vec; -pub struct LanguageNodeJsPlugin; +pub struct JavaScriptNodeJsPlugin; -impl LanguagePlugin for LanguageNodeJsPlugin { +impl LanguagePlugin for JavaScriptNodeJsPlugin { fn get_order(&self) -> i32 { 13 } diff --git a/src-tauri/src/plugins/manager.rs b/src-tauri/src/plugins/manager.rs index baf698f..53050d1 100644 --- a/src-tauri/src/plugins/manager.rs +++ b/src-tauri/src/plugins/manager.rs @@ -4,7 +4,7 @@ use crate::plugins::c::CPlugin; use crate::plugins::clojure::ClojurePlugin; use crate::plugins::go::GoPlugin; use crate::plugins::java::JavaPlugin; -use crate::plugins::javascript_nodejs::LanguageNodeJsPlugin; +use crate::plugins::javascript_nodejs::JavaScriptNodeJsPlugin; use crate::plugins::kotlin::KotlinPlugin; use crate::plugins::nodejs::NodeJSPlugin; use crate::plugins::python2::Python2Plugin; @@ -14,6 +14,7 @@ use crate::plugins::rust::RustPlugin; use crate::plugins::scala::ScalaPlugin; use crate::plugins::shell::ShellPlugin; use crate::plugins::swift::SwiftPlugin; +use crate::plugins::typescript_nodejs::TypeScriptNodeJsPlugin; use std::collections::HashMap; pub struct PluginManager { @@ -40,7 +41,11 @@ impl PluginManager { plugins.insert("applescript".to_string(), Box::new(AppleScriptPlugin)); plugins.insert( "javascript-nodejs".to_string(), - Box::new(LanguageNodeJsPlugin), + Box::new(JavaScriptNodeJsPlugin), + ); + plugins.insert( + "typescript-nodejs".to_string(), + Box::new(TypeScriptNodeJsPlugin), ); Self { plugins } diff --git a/src-tauri/src/plugins/mod.rs b/src-tauri/src/plugins/mod.rs index 9fc5301..76c237d 100644 --- a/src-tauri/src/plugins/mod.rs +++ b/src-tauri/src/plugins/mod.rs @@ -361,5 +361,6 @@ pub mod rust; pub mod scala; pub mod shell; pub mod swift; +pub mod typescript_nodejs; pub use manager::PluginManager; diff --git a/src-tauri/src/plugins/typescript_nodejs.rs b/src-tauri/src/plugins/typescript_nodejs.rs new file mode 100644 index 0000000..b88cd51 --- /dev/null +++ b/src-tauri/src/plugins/typescript_nodejs.rs @@ -0,0 +1,52 @@ +use super::{LanguagePlugin, PluginConfig}; +use std::vec; + +pub struct TypeScriptNodeJsPlugin; + +impl LanguagePlugin for TypeScriptNodeJsPlugin { + fn get_order(&self) -> i32 { + 16 + } + + fn get_language_name(&self) -> &'static str { + "TypeScript (Node.js)" + } + + fn get_language_key(&self) -> &'static str { + "typescript-nodejs" + } + + fn get_file_extension(&self) -> String { + self.get_config() + .map(|config| config.extension.clone()) + .unwrap_or_else(|| "ts".to_string()) + } + + fn get_version_args(&self) -> Vec<&'static str> { + vec!["--version"] + } + + fn get_path_command(&self) -> String { + "which node".to_string() + } + + fn get_default_config(&self) -> PluginConfig { + PluginConfig { + enabled: true, + language: String::from("typescript-nodejs"), + before_compile: None, + extension: String::from("ts"), + execute_home: None, + run_command: Some(String::from("node $filename")), + after_compile: None, + template: Some(String::from("// 在这里输入 TypeScript (Node.js) 代码")), + timeout: Some(30), + } + } + + fn get_default_command(&self) -> String { + self.get_config() + .and_then(|config| config.run_command.clone()) + .unwrap_or_else(|| "node".to_string()) + } +} diff --git a/src/composables/useCodeMirrorEditor.ts b/src/composables/useCodeMirrorEditor.ts index a97f6cc..69e4a98 100644 --- a/src/composables/useCodeMirrorEditor.ts +++ b/src/composables/useCodeMirrorEditor.ts @@ -184,6 +184,8 @@ export function useCodeMirrorEditor(props: Props) return StreamLanguage.define(clojure) case 'ruby': return StreamLanguage.define(ruby) + case 'typescript-nodejs': + return javascript({typescript: true}) default: return null } From 3b3c80f5f1b955704fdb839b33374cecc32f96e7 Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Tue, 26 Aug 2025 19:28:57 +0800 Subject: [PATCH 2/5] =?UTF-8?q?feat=20(language):=20=E6=94=AF=E6=8C=81=20T?= =?UTF-8?q?ypeScript=20=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + public/icons/typescript.svg | 4 + src-tauri/src/examples/typescript.ts | 259 +++++++++++++++++++++++++++ src-tauri/src/plugins/manager.rs | 2 + src-tauri/src/plugins/mod.rs | 6 + src-tauri/src/plugins/typescript.rs | 77 ++++++++ 6 files changed, 349 insertions(+) create mode 100644 public/icons/typescript.svg create mode 100644 src-tauri/src/examples/typescript.ts create mode 100644 src-tauri/src/plugins/typescript.rs diff --git a/README.md b/README.md index 3160a07..a2180f3 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发 - **Rust** - **Shell** - **Swift** +- **TypeScript** - **TypeScript (Node.js)** ## 安装 diff --git a/public/icons/typescript.svg b/public/icons/typescript.svg new file mode 100644 index 0000000..f275c90 --- /dev/null +++ b/public/icons/typescript.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src-tauri/src/examples/typescript.ts b/src-tauri/src/examples/typescript.ts new file mode 100644 index 0000000..75f2ad8 --- /dev/null +++ b/src-tauri/src/examples/typescript.ts @@ -0,0 +1,259 @@ +// TypeScript 示例代码 - CodeForge 代码执行环境 + +// 接口定义 +interface Person { + name: string; + age: number; + height: number; +} + +// 枚举定义 +enum Weekday { + MONDAY = 1, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY, + SUNDAY +} + +// 类型别名 +type CalculationResult = { + result: number; + operation: string; +}; + +// 函数定义 +function greetUser(name: string): string { + return "Hello, " + name + "! 👋"; +} + +function addNumbers(a: number, b: number): CalculationResult { + return { + result: a + b, + operation: 'addition' + }; +} + +function printArray(arr: any[], label: string): void { + console.log(label + ": " + arr.join(' ')); +} + +function fibonacci(n: number): number { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} + +// 类示例 +class Calculator { + private history: string[] = []; + + public add(a: number, b: number): number { + var result = a + b; + this.history.push(a + " + " + b + " = " + result); + return result; + } + + public getHistory(): string[] { + var copy: string[] = []; + for (var i = 0; i < this.history.length; i++) { + copy.push(this.history[i]); + } + return copy; + } +} + +// 主函数 +function main(): void { + console.log("🎉 欢迎使用 CodeForge!"); + console.log("Welcome to CodeForge!"); + console.log(""); + + console.log("========================================="); + console.log(" CodeForge TypeScript "); + console.log("========================================="); + console.log(""); + + // 基本输出示例 + console.log("✅ TypeScript 运行成功! (TypeScript is working!)"); + console.log("⚡ 这是 TypeScript 程序 (This is TypeScript program)"); + console.log(""); + + // 变量操作(强类型) + var name: string = "CodeForge"; + var version: string = "TypeScript"; + var number1: number = 10; + var number2: number = 20; + var calculation: CalculationResult = addNumbers(number1, number2); + + console.log("🔢 简单计算 (Simple calculation):"); + console.log(number1 + " + " + number2 + " = " + calculation.result); + console.log(""); + + // 字符串操作 + console.log("📝 字符串操作 (String operations):"); + console.log("平台名称 (Platform): " + name); + console.log("语言版本 (Language): " + version); + console.log("完整信息 (Full info): " + name + " - " + version); + console.log(""); + + // 循环示例 + console.log("🔄 循环输出 (Loop output):"); + for (var i = 1; i <= 5; i++) { + console.log("第 " + i + " 次输出 (Output #" + i + "): Hello from CodeForge!"); + } + console.log(""); + + // 数组操作(强类型数组) + console.log("🍎 数组示例 (Array example):"); + var fruits: string[] = ["苹果", "香蕉", "橙子", "葡萄"]; + for (var j = 0; j < fruits.length; j++) { + console.log((j + 1) + ". " + fruits[j]); + } + console.log(""); + + // 条件判断 + var score: number = 85; + console.log("📊 成绩评估 (Score evaluation):"); + if (score >= 90) { + console.log("优秀! (Excellent!)"); + } else if (score >= 80) { + console.log("良好! (Good!)"); + } else if (score >= 60) { + console.log("及格 (Pass)"); + } else { + console.log("需要努力 (Need improvement)"); + } + console.log(""); + + // 对象和接口示例 + console.log("👤 对象和接口示例 (Object and Interface example):"); + var person: Person = { + name: "张三", + age: 25, + height: 175.5 + }; + + console.log("姓名: " + person.name + ", 年龄: " + person.age + ", 身高: " + person.height + " cm"); + console.log(""); + + // 函数示例 + console.log("🎭 函数示例 (Function example):"); + console.log(greetUser("CodeForge用户")); + console.log(""); + + // 数组方法示例 + console.log("💾 数组操作示例 (Array operations example):"); + var dynamicArray: number[] = []; + for (var k = 0; k < 5; k++) { + dynamicArray.push((k + 1) * 10); + } + printArray(dynamicArray, "动态数组"); + + // 手动实现 map 功能 + var squares: number[] = []; + for (var l = 0; l < dynamicArray.length; l++) { + squares.push(dynamicArray[l] * dynamicArray[l]); + } + + // 手动实现 filter 功能 + var evenNumbers: number[] = []; + for (var m = 0; m < dynamicArray.length; m++) { + if (dynamicArray[m] % 20 === 0) { + evenNumbers.push(dynamicArray[m]); + } + } + + printArray(squares, "平方数"); + printArray(evenNumbers, "能被20整除的数"); + console.log(""); + + // 递归示例 + console.log("🔄 递归示例 (Recursion example):"); + var fibN: number = 7; + var fibResult: number = fibonacci(fibN); + console.log("斐波那契数列第" + fibN + "项: " + fibResult); + console.log(""); + + // 数学库示例 + console.log("📐 数学库示例 (Math library example):"); + var angle: number = 45.0; + var radians: number = (angle * Math.PI) / 180.0; + console.log("sin(" + angle + "°) = " + Math.sin(radians).toFixed(4)); + console.log("cos(" + angle + "°) = " + Math.cos(radians).toFixed(4)); + console.log("sqrt(16) = " + Math.sqrt(16).toFixed(2)); + console.log(""); + + // 位操作示例 + console.log("🔧 位操作示例 (Bitwise operations):"); + var a: number = 12; // 1100 in binary + var b: number = 10; // 1010 in binary + console.log(a + " & " + b + " = " + (a & b) + " (AND)"); + console.log(a + " | " + b + " = " + (a | b) + " (OR)"); + console.log(a + " ^ " + b + " = " + (a ^ b) + " (XOR)"); + console.log("~" + a + " = " + (~a) + " (NOT)"); + console.log(""); + + // 枚举示例 + console.log("📋 枚举示例 (Enum example):"); + var today: Weekday = Weekday.WEDNESDAY; + console.log("今天是星期" + today); + console.log(""); + + // 类示例 + console.log("🎯 类示例 (Class example):"); + var calc = new Calculator(); + calc.add(5, 3); + calc.add(10, 7); + console.log("计算历史: " + calc.getHistory().join(", ")); + console.log(""); + + // 泛型函数示例 + function identity(arg: T): T { + return arg; + } + + console.log("🔧 泛型函数示例 (Generic function example):"); + console.log("字符串泛型: " + identity("Hello")); + console.log("数字泛型: " + identity(42)); + console.log(""); + + // 联合类型示例 + function formatValue(value: string | number): string { + if (typeof value === "string") { + return "字符串: " + value; + } else { + return "数字: " + value.toString(); + } + } + + console.log("🎲 联合类型示例 (Union type example):"); + console.log(formatValue("TypeScript")); + console.log(formatValue(2024)); + console.log(""); + + // 回调函数示例(模拟异步操作) + console.log("⚡ 回调函数示例 (Callback example):"); + function simulateAsync(callback: (message: string) => void): void { + setTimeout(function() { + callback("异步操作完成!"); + }, 100); + } + + simulateAsync(function(message: string) { + console.log(message); + console.log(""); + + console.log("🎯 CodeForge TypeScript 代码执行完成!"); + console.log("🎯 CodeForge TypeScript execution completed!"); + console.log(""); + console.log("感谢使用 CodeForge 代码执行环境! 🚀"); + console.log("Thank you for using CodeForge! 🚀"); + }); +} + +// 运行主函数 +main(); \ No newline at end of file diff --git a/src-tauri/src/plugins/manager.rs b/src-tauri/src/plugins/manager.rs index 53050d1..a3af7fe 100644 --- a/src-tauri/src/plugins/manager.rs +++ b/src-tauri/src/plugins/manager.rs @@ -14,6 +14,7 @@ use crate::plugins::rust::RustPlugin; use crate::plugins::scala::ScalaPlugin; use crate::plugins::shell::ShellPlugin; use crate::plugins::swift::SwiftPlugin; +use crate::plugins::typescript::TypeScriptPlugin; use crate::plugins::typescript_nodejs::TypeScriptNodeJsPlugin; use std::collections::HashMap; @@ -39,6 +40,7 @@ impl PluginManager { plugins.insert("c".to_string(), Box::new(CPlugin)); plugins.insert("ruby".to_string(), Box::new(RubyPlugin)); plugins.insert("applescript".to_string(), Box::new(AppleScriptPlugin)); + plugins.insert("typescript".to_string(), Box::new(TypeScriptPlugin)); plugins.insert( "javascript-nodejs".to_string(), Box::new(JavaScriptNodeJsPlugin), diff --git a/src-tauri/src/plugins/mod.rs b/src-tauri/src/plugins/mod.rs index 76c237d..18ece3a 100644 --- a/src-tauri/src/plugins/mod.rs +++ b/src-tauri/src/plugins/mod.rs @@ -216,6 +216,11 @@ pub trait LanguagePlugin: Send + Sync { } let processed_cmd = before_cmd.replace("$filename", file_path); + info!( + "执行代码 -> 插件 [ {} ] 处理 pre_execute_hook 处理命令 {}", + self.get_language_key(), + processed_cmd + ); self.handle_environment_setup(&processed_cmd)?; } } @@ -361,6 +366,7 @@ pub mod rust; pub mod scala; pub mod shell; pub mod swift; +pub mod typescript; pub mod typescript_nodejs; pub use manager::PluginManager; diff --git a/src-tauri/src/plugins/typescript.rs b/src-tauri/src/plugins/typescript.rs new file mode 100644 index 0000000..3117787 --- /dev/null +++ b/src-tauri/src/plugins/typescript.rs @@ -0,0 +1,77 @@ +use super::{LanguagePlugin, PluginConfig}; +use std::vec; + +pub struct TypeScriptPlugin; + +impl LanguagePlugin for TypeScriptPlugin { + fn get_order(&self) -> i32 { + 17 + } + + fn get_language_name(&self) -> &'static str { + "TypeScript" + } + + fn get_language_key(&self) -> &'static str { + "typescript" + } + + fn get_file_extension(&self) -> String { + self.get_config() + .map(|config| config.extension.clone()) + .unwrap_or_else(|| "ts".to_string()) + } + + fn get_version_args(&self) -> Vec<&'static str> { + vec!["--version"] + } + + fn get_path_command(&self) -> String { + "which tsc".to_string() + } + + fn get_execute_args(&self, file_path: &str) -> Vec { + if let Some(config) = self.get_config() { + if let Some(run_cmd) = &config.run_command { + let processed_cmd = if run_cmd.contains("$classname") { + let class_name = if file_path.ends_with(&self.get_file_extension().to_string()) + { + file_path.replace(&self.get_file_extension().to_string(), ".js") + } else { + file_path.to_string() + }; + run_cmd.replace("$classname", &class_name) + } else { + run_cmd.replace("$filename", file_path) + }; + + return processed_cmd + .split_whitespace() + .skip(1) + .map(|s| s.to_string()) + .collect(); + } + } + vec![file_path.to_string()] + } + + fn get_default_config(&self) -> PluginConfig { + PluginConfig { + enabled: true, + language: String::from("typescript"), + before_compile: Some(String::from("tsc $filename")), + extension: String::from("ts"), + execute_home: None, + run_command: Some(String::from("node $classname")), + after_compile: Some(String::from("rm -f *.js")), + template: Some(String::from("// 在这里输入 TypeScript 代码")), + timeout: Some(30), + } + } + + fn get_default_command(&self) -> String { + self.get_config() + .and_then(|config| config.run_command.clone()) + .unwrap_or_else(|| "tsc".to_string()) + } +} From 972a81cfaa85a6040545f87b3749b0bb357de681 Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Tue, 26 Aug 2025 19:34:34 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix=20(core):=20=E4=BF=AE=E5=A4=8D=20Pre-ex?= =?UTF-8?q?ecution=20=E6=9C=AA=E5=8F=8D=E9=A6=88=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/plugins/mod.rs | 25 +++++++++++++++++++++---- src/composables/useCodeMirrorEditor.ts | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src-tauri/src/plugins/mod.rs b/src-tauri/src/plugins/mod.rs index 18ece3a..2bdca3c 100644 --- a/src-tauri/src/plugins/mod.rs +++ b/src-tauri/src/plugins/mod.rs @@ -307,6 +307,8 @@ pub trait LanguagePlugin: Send + Sync { } fn execute_cross_platform_command(&self, command: &str) -> Result<(), String> { + info!("执行命令: {}", command); + let output = if cfg!(target_os = "windows") { std::process::Command::new("cmd") .args(["/C", command]) @@ -319,11 +321,26 @@ pub trait LanguagePlugin: Send + Sync { let output = output.map_err(|e| format!("执行命令失败: {}", e))?; + debug!("命令退出状态: {:?}", output.status); + debug!("命令标准输出: {}", String::from_utf8_lossy(&output.stdout)); + debug!("命令标准错误: {}", String::from_utf8_lossy(&output.stderr)); + if !output.status.success() { - return Err(format!( - "命令执行失败: {}", - String::from_utf8_lossy(&output.stderr) - )); + let stderr = String::from_utf8_lossy(&output.stderr); + let stdout = String::from_utf8_lossy(&output.stdout); + + let error_msg = if !stderr.is_empty() { + stderr.to_string() + } else if !stdout.is_empty() { + stdout.to_string() + } else { + format!( + "命令执行失败,退出代码: {}", + output.status.code().unwrap_or(-1) + ) + }; + + return Err(format!("命令执行失败: {}", error_msg)); } Ok(()) diff --git a/src/composables/useCodeMirrorEditor.ts b/src/composables/useCodeMirrorEditor.ts index 69e4a98..954ab52 100644 --- a/src/composables/useCodeMirrorEditor.ts +++ b/src/composables/useCodeMirrorEditor.ts @@ -184,6 +184,7 @@ export function useCodeMirrorEditor(props: Props) return StreamLanguage.define(clojure) case 'ruby': return StreamLanguage.define(ruby) + case 'typescript': case 'typescript-nodejs': return javascript({typescript: true}) default: From 9632d075a77be0370ab7ce26b25ddd11c0e3af24 Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Tue, 26 Aug 2025 19:39:11 +0800 Subject: [PATCH 4/5] =?UTF-8?q?feat=20(language):=20=E4=BC=98=E5=8C=96=20T?= =?UTF-8?q?ypeScript=20=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src-tauri/src/plugins/typescript.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/plugins/typescript.rs b/src-tauri/src/plugins/typescript.rs index 3117787..4661a04 100644 --- a/src-tauri/src/plugins/typescript.rs +++ b/src-tauri/src/plugins/typescript.rs @@ -36,7 +36,7 @@ impl LanguagePlugin for TypeScriptPlugin { let processed_cmd = if run_cmd.contains("$classname") { let class_name = if file_path.ends_with(&self.get_file_extension().to_string()) { - file_path.replace(&self.get_file_extension().to_string(), ".js") + file_path.replace(&self.get_file_extension().to_string(), "js") } else { file_path.to_string() }; @@ -59,7 +59,7 @@ impl LanguagePlugin for TypeScriptPlugin { PluginConfig { enabled: true, language: String::from("typescript"), - before_compile: Some(String::from("tsc $filename")), + before_compile: Some(String::from("tsc --lib es2017,dom --skipLibCheck $filename")), extension: String::from("ts"), execute_home: None, run_command: Some(String::from("node $classname")), From 0b78d70274a9820df0368f93c8e8ca97aea81c8c Mon Sep 17 00:00:00 2001 From: qianmoQ Date: Tue, 26 Aug 2025 20:25:25 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat=20(language):=20=E6=94=AF=E6=8C=81=20T?= =?UTF-8?q?ypeScript=20By=20Browser=20=E5=BC=95=E6=93=8E=E8=AF=AD=E8=A8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + public/icons/typescript-browser.svg | 7 + src-tauri/src/examples/typescript-browser.ts | 259 +++++++++++++++++++ src-tauri/src/examples/typescript-nodejs.ts | 14 +- src-tauri/src/plugins/manager.rs | 5 + src-tauri/src/plugins/mod.rs | 18 +- src-tauri/src/plugins/typescript.rs | 4 +- src-tauri/src/plugins/typescript_browser.rs | 81 ++++++ src/composables/useCodeMirrorEditor.ts | 1 + 9 files changed, 374 insertions(+), 16 deletions(-) create mode 100644 public/icons/typescript-browser.svg create mode 100644 src-tauri/src/examples/typescript-browser.ts create mode 100644 src-tauri/src/plugins/typescript_browser.rs diff --git a/README.md b/README.md index a2180f3..5585b22 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ CodeForge 是一款轻量级、高性能的桌面代码执行器,专为开发 - **Shell** - **Swift** - **TypeScript** +- **TypeScript (Browser)** - **TypeScript (Node.js)** ## 安装 diff --git a/public/icons/typescript-browser.svg b/public/icons/typescript-browser.svg new file mode 100644 index 0000000..3ec4c71 --- /dev/null +++ b/public/icons/typescript-browser.svg @@ -0,0 +1,7 @@ + + + + + Browser + + \ No newline at end of file diff --git a/src-tauri/src/examples/typescript-browser.ts b/src-tauri/src/examples/typescript-browser.ts new file mode 100644 index 0000000..7f584c6 --- /dev/null +++ b/src-tauri/src/examples/typescript-browser.ts @@ -0,0 +1,259 @@ +// TypeScript Browser 示例代码 - CodeForge 代码执行环境 + +// 接口定义 +interface Person { + name: string; + age: number; + height: number; +} + +// 枚举定义 +enum Weekday { + MONDAY = 1, + TUESDAY, + WEDNESDAY, + THURSDAY, + FRIDAY, + SATURDAY, + SUNDAY +} + +// 类型别名 +type CalculationResult = { + result: number; + operation: string; +}; + +// 函数定义 +function greetUser(name: string): string { + return "Hello, " + name + "! 👋"; +} + +function addNumbers(a: number, b: number): CalculationResult { + return { + result: a + b, + operation: 'addition' + }; +} + +function printArray(arr: any[], label: string): void { + console.log(label + ": " + arr.join(' ')); +} + +function fibonacci(n: number): number { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); +} + +// 类示例 +class Calculator { + private history: string[] = []; + + public add(a: number, b: number): number { + var result = a + b; + this.history.push(a + " + " + b + " = " + result); + return result; + } + + public getHistory(): string[] { + var copy: string[] = []; + for (var i = 0; i < this.history.length; i++) { + copy.push(this.history[i]); + } + return copy; + } +} + +// 主函数 +function main(): void { + console.log("🎉 欢迎使用 CodeForge!"); + console.log("Welcome to CodeForge!"); + console.log(""); + + console.log("========================================="); + console.log(" CodeForge TypeScript Browser "); + console.log("========================================="); + console.log(""); + + // 基本输出示例 + console.log("✅ TypeScript 运行成功! (TypeScript is working!)"); + console.log("⚡ 这是 TypeScript 程序 (This is TypeScript program)"); + console.log(""); + + // 变量操作(强类型) + var name: string = "CodeForge"; + var version: string = "TypeScript"; + var number1: number = 10; + var number2: number = 20; + var calculation: CalculationResult = addNumbers(number1, number2); + + console.log("🔢 简单计算 (Simple calculation):"); + console.log(number1 + " + " + number2 + " = " + calculation.result); + console.log(""); + + // 字符串操作 + console.log("📝 字符串操作 (String operations):"); + console.log("平台名称 (Platform): " + name); + console.log("语言版本 (Language): " + version); + console.log("完整信息 (Full info): " + name + " - " + version); + console.log(""); + + // 循环示例 + console.log("🔄 循环输出 (Loop output):"); + for (var i = 1; i <= 5; i++) { + console.log("第 " + i + " 次输出 (Output #" + i + "): Hello from CodeForge!"); + } + console.log(""); + + // 数组操作(强类型数组) + console.log("🍎 数组示例 (Array example):"); + var fruits: string[] = ["苹果", "香蕉", "橙子", "葡萄"]; + for (var j = 0; j < fruits.length; j++) { + console.log((j + 1) + ". " + fruits[j]); + } + console.log(""); + + // 条件判断 + var score: number = 85; + console.log("📊 成绩评估 (Score evaluation):"); + if (score >= 90) { + console.log("优秀! (Excellent!)"); + } else if (score >= 80) { + console.log("良好! (Good!)"); + } else if (score >= 60) { + console.log("及格 (Pass)"); + } else { + console.log("需要努力 (Need improvement)"); + } + console.log(""); + + // 对象和接口示例 + console.log("👤 对象和接口示例 (Object and Interface example):"); + var person: Person = { + name: "张三", + age: 25, + height: 175.5 + }; + + console.log("姓名: " + person.name + ", 年龄: " + person.age + ", 身高: " + person.height + " cm"); + console.log(""); + + // 函数示例 + console.log("🎭 函数示例 (Function example):"); + console.log(greetUser("CodeForge用户")); + console.log(""); + + // 数组方法示例 + console.log("💾 数组操作示例 (Array operations example):"); + var dynamicArray: number[] = []; + for (var k = 0; k < 5; k++) { + dynamicArray.push((k + 1) * 10); + } + printArray(dynamicArray, "动态数组"); + + // 手动实现 map 功能 + var squares: number[] = []; + for (var l = 0; l < dynamicArray.length; l++) { + squares.push(dynamicArray[l] * dynamicArray[l]); + } + + // 手动实现 filter 功能 + var evenNumbers: number[] = []; + for (var m = 0; m < dynamicArray.length; m++) { + if (dynamicArray[m] % 20 === 0) { + evenNumbers.push(dynamicArray[m]); + } + } + + printArray(squares, "平方数"); + printArray(evenNumbers, "能被20整除的数"); + console.log(""); + + // 递归示例 + console.log("🔄 递归示例 (Recursion example):"); + var fibN: number = 7; + var fibResult: number = fibonacci(fibN); + console.log("斐波那契数列第" + fibN + "项: " + fibResult); + console.log(""); + + // 数学库示例 + console.log("📐 数学库示例 (Math library example):"); + var angle: number = 45.0; + var radians: number = (angle * Math.PI) / 180.0; + console.log("sin(" + angle + "°) = " + Math.sin(radians).toFixed(4)); + console.log("cos(" + angle + "°) = " + Math.cos(radians).toFixed(4)); + console.log("sqrt(16) = " + Math.sqrt(16).toFixed(2)); + console.log(""); + + // 位操作示例 + console.log("🔧 位操作示例 (Bitwise operations):"); + var a: number = 12; // 1100 in binary + var b: number = 10; // 1010 in binary + console.log(a + " & " + b + " = " + (a & b) + " (AND)"); + console.log(a + " | " + b + " = " + (a | b) + " (OR)"); + console.log(a + " ^ " + b + " = " + (a ^ b) + " (XOR)"); + console.log("~" + a + " = " + (~a) + " (NOT)"); + console.log(""); + + // 枚举示例 + console.log("📋 枚举示例 (Enum example):"); + var today: Weekday = Weekday.WEDNESDAY; + console.log("今天是星期" + today); + console.log(""); + + // 类示例 + console.log("🎯 类示例 (Class example):"); + var calc = new Calculator(); + calc.add(5, 3); + calc.add(10, 7); + console.log("计算历史: " + calc.getHistory().join(", ")); + console.log(""); + + // 泛型函数示例 + function identity(arg: T): T { + return arg; + } + + console.log("🔧 泛型函数示例 (Generic function example):"); + console.log("字符串泛型: " + identity("Hello")); + console.log("数字泛型: " + identity(42)); + console.log(""); + + // 联合类型示例 + function formatValue(value: string | number): string { + if (typeof value === "string") { + return "字符串: " + value; + } else { + return "数字: " + value.toString(); + } + } + + console.log("🎲 联合类型示例 (Union type example):"); + console.log(formatValue("TypeScript")); + console.log(formatValue(2024)); + console.log(""); + + // 回调函数示例(模拟异步操作) + console.log("⚡ 回调函数示例 (Callback example):"); + function simulateAsync(callback: (message: string) => void): void { + setTimeout(function() { + callback("异步操作完成!"); + }, 100); + } + + simulateAsync(function(message: string) { + console.log(message); + console.log(""); + + console.log("🎯 CodeForge TypeScript 代码执行完成!"); + console.log("🎯 CodeForge TypeScript execution completed!"); + console.log(""); + console.log("感谢使用 CodeForge 代码执行环境! 🚀"); + console.log("Thank you for using CodeForge! 🚀"); + }); +} + +// 运行主函数 +main(); \ No newline at end of file diff --git a/src-tauri/src/examples/typescript-nodejs.ts b/src-tauri/src/examples/typescript-nodejs.ts index b87a761..febbabf 100644 --- a/src-tauri/src/examples/typescript-nodejs.ts +++ b/src-tauri/src/examples/typescript-nodejs.ts @@ -1,4 +1,4 @@ -// JavaScript 示例代码 - CodeForge 代码执行环境 +// TypeScript Node.js 示例代码 - CodeForge 代码执行环境 function greetUser(name) { return `Hello, ${name}! 👋`; @@ -41,18 +41,18 @@ function main() { console.log(""); console.log("========================================="); - console.log(" CodeForge JavaScript "); + console.log(" CodeForge TypeScript Node.js "); console.log("========================================="); console.log(""); // 基本输出示例 - console.log("✅ JavaScript 运行成功! (JavaScript is working!)"); - console.log("⚡ 这是 JavaScript 程序 (This is JavaScript program)"); + console.log("✅ TypeScript 运行成功! (TypeScript is working!)"); + console.log("⚡ 这是 TypeScript 程序 (This is TypeScript program)"); console.log(""); // 变量操作 const name = "CodeForge"; - const version = "JavaScript"; + const version = "TypeScript"; const number1 = 10; const number2 = 20; const calculation = addNumbers(number1, number2); @@ -204,8 +204,8 @@ function main() { console.log("计算历史:", calc.getHistory()); console.log(""); - console.log("🎯 CodeForge JavaScript 代码执行完成!"); - console.log("🎯 CodeForge JavaScript execution completed!"); + console.log("🎯 CodeForge TypeScript 代码执行完成!"); + console.log("🎯 CodeForge TypeScript execution completed!"); console.log(""); console.log("感谢使用 CodeForge 代码执行环境! 🚀"); console.log("Thank you for using CodeForge! 🚀"); diff --git a/src-tauri/src/plugins/manager.rs b/src-tauri/src/plugins/manager.rs index a3af7fe..8b66fbf 100644 --- a/src-tauri/src/plugins/manager.rs +++ b/src-tauri/src/plugins/manager.rs @@ -15,6 +15,7 @@ use crate::plugins::scala::ScalaPlugin; use crate::plugins::shell::ShellPlugin; use crate::plugins::swift::SwiftPlugin; use crate::plugins::typescript::TypeScriptPlugin; +use crate::plugins::typescript_browser::TypeScriptBrowserPlugin; use crate::plugins::typescript_nodejs::TypeScriptNodeJsPlugin; use std::collections::HashMap; @@ -49,6 +50,10 @@ impl PluginManager { "typescript-nodejs".to_string(), Box::new(TypeScriptNodeJsPlugin), ); + plugins.insert( + "typescript-browser".to_string(), + Box::new(TypeScriptBrowserPlugin), + ); Self { plugins } } diff --git a/src-tauri/src/plugins/mod.rs b/src-tauri/src/plugins/mod.rs index 2bdca3c..082ec17 100644 --- a/src-tauri/src/plugins/mod.rs +++ b/src-tauri/src/plugins/mod.rs @@ -124,16 +124,17 @@ pub trait LanguagePlugin: Send + Sync { let language_name = self.get_language_key(); // 查找匹配的插件配置 - let found_config = plugins + if let Some(found_config) = plugins .iter() .find(|config| config.language == language_name) - .cloned(); - - debug!( - "执行代码 -> 获取插件 [ {} ] 配置 {:?}", - language_name, found_config - ); - return found_config; + .cloned() + { + debug!( + "执行代码 -> 获取插件 [ {} ] 配置 {:?}", + language_name, found_config + ); + return Some(found_config); + } } } @@ -384,6 +385,7 @@ pub mod scala; pub mod shell; pub mod swift; pub mod typescript; +pub mod typescript_browser; pub mod typescript_nodejs; pub use manager::PluginManager; diff --git a/src-tauri/src/plugins/typescript.rs b/src-tauri/src/plugins/typescript.rs index 4661a04..f7a51fe 100644 --- a/src-tauri/src/plugins/typescript.rs +++ b/src-tauri/src/plugins/typescript.rs @@ -59,7 +59,9 @@ impl LanguagePlugin for TypeScriptPlugin { PluginConfig { enabled: true, language: String::from("typescript"), - before_compile: Some(String::from("tsc --lib es2017,dom --skipLibCheck $filename")), + before_compile: Some(String::from( + "tsc --lib es2017,dom --skipLibCheck $filename", + )), extension: String::from("ts"), execute_home: None, run_command: Some(String::from("node $classname")), diff --git a/src-tauri/src/plugins/typescript_browser.rs b/src-tauri/src/plugins/typescript_browser.rs new file mode 100644 index 0000000..414cffb --- /dev/null +++ b/src-tauri/src/plugins/typescript_browser.rs @@ -0,0 +1,81 @@ +use super::{LanguagePlugin, PluginConfig}; +use std::vec; + +pub struct TypeScriptBrowserPlugin; + +impl LanguagePlugin for TypeScriptBrowserPlugin { + fn get_order(&self) -> i32 { + 16 + } + + fn get_language_name(&self) -> &'static str { + "TypeScript (Browser)" + } + + fn get_language_key(&self) -> &'static str { + "typescript-browser" + } + + fn get_file_extension(&self) -> String { + self.get_config() + .map(|config| config.extension.clone()) + .unwrap_or_else(|| "ts".to_string()) + } + + fn get_version_args(&self) -> Vec<&'static str> { + vec!["--version"] + } + + fn get_path_command(&self) -> String { + "which tsc".to_string() + } + + fn get_execute_args(&self, file_path: &str) -> Vec { + if let Some(config) = self.get_config() { + if let Some(run_cmd) = &config.run_command { + let processed_cmd = if run_cmd.contains("$classname") { + let class_name = if file_path.ends_with(&self.get_file_extension().to_string()) + { + file_path.replace(&self.get_file_extension().to_string(), "js") + } else { + file_path.to_string() + }; + run_cmd.replace("$classname", &class_name) + } else { + run_cmd.replace("$filename", file_path) + }; + + return processed_cmd + .split_whitespace() + .skip(1) + .map(|s| s.to_string()) + .collect(); + } + } + vec![file_path.to_string()] + } + + fn get_default_config(&self) -> PluginConfig { + PluginConfig { + enabled: true, + language: String::from("typescript-browser"), + before_compile: Some(String::from( + "tsc --lib es2017,dom --skipLibCheck $filename", + )), + extension: String::from("ts"), + execute_home: None, + run_command: Some(String::from( + "echo ", + )), + after_compile: Some(String::from("rm -f *.js")), + template: Some(String::from("// 在这里输入 TypeScript (Browser) 代码")), + timeout: Some(30), + } + } + + fn get_default_command(&self) -> String { + self.get_config() + .and_then(|config| config.run_command.clone()) + .unwrap_or_else(|| "tsc".to_string()) + } +} diff --git a/src/composables/useCodeMirrorEditor.ts b/src/composables/useCodeMirrorEditor.ts index 954ab52..dceabc0 100644 --- a/src/composables/useCodeMirrorEditor.ts +++ b/src/composables/useCodeMirrorEditor.ts @@ -185,6 +185,7 @@ export function useCodeMirrorEditor(props: Props) case 'ruby': return StreamLanguage.define(ruby) case 'typescript': + case 'typescript-browser': case 'typescript-nodejs': return javascript({typescript: true}) default: