diff --git a/apps/executeJS/src-tauri/src/commands.rs b/apps/executeJS/src-tauri/src/commands.rs index 7fb5da7..2cafdaa 100644 --- a/apps/executeJS/src-tauri/src/commands.rs +++ b/apps/executeJS/src-tauri/src/commands.rs @@ -1,4 +1,4 @@ -use crate::js_executor::{execute_javascript_code, JsExecutionResult, JsExecutorState}; +use crate::js_executor::{execute_javascript_code, JsExecutionResult}; use serde::{Deserialize, Serialize}; use tauri::State; @@ -10,70 +10,25 @@ pub struct AppInfo { pub author: String, } -// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/ #[tauri::command] -pub fn greet(name: &str) -> String { - format!("Hello, {}! You've been greeted from Rust!", name) -} - -#[tauri::command] -pub async fn execute_js( - code: &str, - state: State<'_, JsExecutorState>, -) -> Result { +pub async fn execute_js(code: &str) -> Result { let result = execute_javascript_code(code).await; - // 실행 결과를 히스토리에 추가 - state.add_execution(result.clone()); - if result.success { Ok(result) } else { - Err(result + let error_message = result .error - .unwrap_or_else(|| "알 수 없는 오류".to_string())) - } -} - -#[tauri::command] -pub fn get_js_execution_history(state: State) -> Vec { - state.get_history() -} - -#[tauri::command] -pub fn clear_js_execution_history(state: State) -> Result<(), String> { - state.clear_history(); - Ok(()) -} - -#[tauri::command] -pub fn save_js_code(code: &str, filename: &str) -> Result { - use std::fs; - use std::path::Path; - - let code_dir = Path::new("saved_codes"); - if !code_dir.exists() { - fs::create_dir_all(code_dir).map_err(|e| format!("디렉토리 생성 실패: {}", e))?; - } - - let file_path = code_dir.join(filename); - fs::write(&file_path, code).map_err(|e| format!("파일 저장 실패: {}", e))?; - - Ok(format!("코드가 {}에 저장되었습니다", file_path.display())) -} - -#[tauri::command] -pub fn load_js_code(filename: &str) -> Result { - use std::fs; - use std::path::Path; - - let file_path = Path::new("saved_codes").join(filename); - - if !file_path.exists() { - return Err("파일을 찾을 수 없습니다".to_string()); + .unwrap_or_else(|| "알 수 없는 오류".to_string()); + + Err(JsExecutionResult { + code: code.to_string(), + result: error_message.clone(), + timestamp: chrono::Utc::now(), + success: false, + error: Some(error_message.clone()), + }) } - - fs::read_to_string(&file_path).map_err(|e| format!("파일 읽기 실패: {}", e)) } #[tauri::command] diff --git a/apps/executeJS/src-tauri/src/deno_runtime.rs b/apps/executeJS/src-tauri/src/deno_runtime.rs index cfa9f28..8167c33 100644 --- a/apps/executeJS/src-tauri/src/deno_runtime.rs +++ b/apps/executeJS/src-tauri/src/deno_runtime.rs @@ -146,22 +146,8 @@ impl DenoExecutor { return Err(anyhow::anyhow!("Bootstrap 실행 실패: {}", e)); } - // JavaScript 코드를 즉시 실행 함수로 래핑 - let wrapped_code = format!( - r#" - (async () => {{ - try {{ - {} - }} catch (error) {{ - console.error('Error:', error.message); - }} - }})(); - "#, - code - ); - // 코드 실행 - let result = js_runtime.execute_script("[executejs:user_code]", wrapped_code)?; + let result = js_runtime.execute_script("[executejs:user_code]", code)?; // 이벤트 루프 실행 (Promise 처리) - 블로킹 방식으로 변경 let rt = tokio::runtime::Handle::current(); diff --git a/apps/executeJS/src-tauri/src/js_executor.rs b/apps/executeJS/src-tauri/src/js_executor.rs index d111b37..26a5606 100644 --- a/apps/executeJS/src-tauri/src/js_executor.rs +++ b/apps/executeJS/src-tauri/src/js_executor.rs @@ -12,50 +12,6 @@ pub struct JsExecutionResult { pub error: Option, } -#[derive(Debug)] -pub struct JsExecutorState { - pub history: Mutex>, - pub max_history: usize, -} - -impl JsExecutorState { - pub fn new(max_history: usize) -> Self { - Self { - history: Mutex::new(VecDeque::new()), - max_history, - } - } - - pub fn add_execution(&self, result: JsExecutionResult) { - if let Ok(mut history) = self.history.lock() { - history.push_back(result); - if history.len() > self.max_history { - history.pop_front(); - } - } - } - - pub fn get_history(&self) -> Vec { - if let Ok(history) = self.history.lock() { - history.iter().cloned().collect() - } else { - vec![] - } - } - - pub fn clear_history(&self) { - if let Ok(mut history) = self.history.lock() { - history.clear(); - } - } -} - -impl Default for JsExecutorState { - fn default() -> Self { - Self::new(100) // 최대 100개의 실행 기록 보관 - } -} - pub async fn execute_javascript_code(code: &str) -> JsExecutionResult { let timestamp = chrono::Utc::now(); @@ -84,7 +40,7 @@ pub async fn execute_javascript_code(code: &str) -> JsExecutionResult { result: String::new(), timestamp, success: false, - error: Some(format!("JavaScript 실행 오류: {}", error)), + error: Some(format!("{}", error)), }, } } @@ -92,15 +48,13 @@ pub async fn execute_javascript_code(code: &str) -> JsExecutionResult { /// Deno를 사용한 JavaScript 코드 실행 async fn execute_with_deno(code: &str) -> Result> { // DenoExecutor 생성 - let mut executor = DenoExecutor::new() - .await - .map_err(|e| format!("Deno 런타임 초기화 실패: {}", e))?; + let mut executor = DenoExecutor::new().await.map_err(|e| format!("{}", e))?; // 코드 실행 let result = executor .execute_script("index.js", code) .await - .map_err(|e| format!("JavaScript 실행 실패: {}", e))?; + .map_err(|e| format!("{}", e))?; Ok(result) } diff --git a/apps/executeJS/src-tauri/src/lib.rs b/apps/executeJS/src-tauri/src/lib.rs index 9bfd6af..ee6f008 100644 --- a/apps/executeJS/src-tauri/src/lib.rs +++ b/apps/executeJS/src-tauri/src/lib.rs @@ -37,8 +37,6 @@ pub fn run() { window.close_devtools(); } - app_handle.manage(js_executor::JsExecutorState::default()); - // 앱 시작 시 초기화 작업 tauri::async_runtime::spawn(async { tracing::info!("ExecuteJS 애플리케이션이 시작되었습니다."); @@ -52,15 +50,7 @@ pub fn run() { tracing::info!("ExecuteJS 애플리케이션이 종료됩니다."); } }) - .invoke_handler(tauri::generate_handler![ - greet, - execute_js, - get_js_execution_history, - clear_js_execution_history, - save_js_code, - load_js_code, - get_app_info - ]) + .invoke_handler(tauri::generate_handler![execute_js, get_app_info]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/apps/executeJS/src/features/execute-code/model.ts b/apps/executeJS/src/features/execute-code/model.ts index 2e26544..367c97b 100644 --- a/apps/executeJS/src/features/execute-code/model.ts +++ b/apps/executeJS/src/features/execute-code/model.ts @@ -20,8 +20,6 @@ export const useExecutionStore = create()( // 코드 실행 executeCode: async (code: string) => { - console.log('executeCode called -', code); - set({ isExecuting: true }); try { @@ -37,15 +35,15 @@ export const useExecutionStore = create()( result, isExecuting: false, }); - } catch (error) { + } catch (error: any) { + //TODO: @ohah 에러 처리 더 명확하게 할 것 const result: JsExecutionResult = { code, - result: '', + result: error?.result ?? '', timestamp: new Date().toISOString(), success: false, - error: error instanceof Error ? error.message : '알 수 없는 오류', + error: error?.error ?? '알 수 없는 오류', }; - set({ result, isExecuting: false, diff --git a/docs/docs/api/commands.mdx b/docs/docs/api/commands.mdx index 3cde8c1..0e694b7 100644 --- a/docs/docs/api/commands.mdx +++ b/docs/docs/api/commands.mdx @@ -4,141 +4,26 @@ ExecuteJS에서 사용할 수 있는 모든 Tauri 명령어를 확인하세요. ## 기본 명령어 -### greet - -인사말을 반환하는 기본 명령어입니다. - -```typescript -import { invoke } from '@tauri-apps/api/core'; - -const message = await invoke('greet', { name: 'World' }); -console.log(message); // "Hello World! You've been greeted from Rust!" -``` - -**매개변수:** -- `name` (string): 인사할 이름 - -**반환값:** -- `string`: 인사 메시지 - ### execute_js -JavaScript 코드를 실행합니다. +자바스크립트에 실행을 요청하는 명령어입니다. ```typescript import { invoke } from '@tauri-apps/api/core'; -const result = await invoke('execute_js', { - code: 'console.log("Hello, World!");' +const result = await invoke('execute_js', { + code: 'console.log("Hello, World!");', }); console.log(result); ``` **매개변수:** -- `code` (string): 실행할 JavaScript 코드 - -**반환값:** -- `JsExecutionResult`: 실행 결과 객체 - -## 실행 기록 관리 - -### get_js_execution_history - -JavaScript 실행 기록을 가져옵니다. - -```typescript -import { invoke } from '@tauri-apps/api/core'; - -const history = await invoke('get_js_execution_history'); -console.log(history); // JsExecutionResult[] -``` - -**반환값:** -- `JsExecutionResult[]`: 실행 기록 배열 - -### clear_js_execution_history - -JavaScript 실행 기록을 모두 삭제합니다. - -```typescript -import { invoke } from '@tauri-apps/api/core'; - -await invoke('clear_js_execution_history'); -``` - -## 코드 저장/로드 - -### save_js_code - -JavaScript 코드를 로컬에 저장합니다. - -```typescript -import { invoke } from '@tauri-apps/api/core'; - -await invoke('save_js_code', { - code: 'console.log("Saved code");' -}); -``` - -**매개변수:** -- `code` (string): 저장할 JavaScript 코드 - -### load_js_code - -저장된 JavaScript 코드를 불러옵니다. - -```typescript -import { invoke } from '@tauri-apps/api/core'; - -const code = await invoke('load_js_code'); -console.log(code); // string -``` - -**반환값:** -- `string`: 저장된 JavaScript 코드 - -## 앱 정보 - -### get_app_info -애플리케이션 정보를 가져옵니다. - -```typescript -import { invoke } from '@tauri-apps/api/core'; - -const appInfo = await invoke('get_app_info'); -console.log(appInfo); -``` +- `code` (string): 실행할 JavaScript 코드 **반환값:** -- `AppInfo`: 애플리케이션 정보 객체 - -## 타입 정의 - -### JsExecutionResult - -```typescript -interface JsExecutionResult { - id: string; - code: string; - result: string; - success: boolean; - timestamp: string; - executionTime: number; -} -``` -### AppInfo - -```typescript -interface AppInfo { - name: string; - version: string; - tauriVersion: string; - platform: string; - arch: string; -} -``` +- `JsExecutionResult`: 실행 결과 객체 ## 에러 처리 @@ -150,4 +35,4 @@ try { } catch (error) { console.error('Execution failed:', error); } -``` \ No newline at end of file +``` diff --git a/docs/docs/guide/development.mdx b/docs/docs/guide/development.mdx index 1cfe188..ba3ad03 100644 --- a/docs/docs/guide/development.mdx +++ b/docs/docs/guide/development.mdx @@ -160,7 +160,7 @@ src/ ### 프론트엔드 기술 스택 -- **상태 관리**: Legend State (반응형 상태 관리) +- **상태 관리**: Zustand (경량 상태 관리) - **UI 라이브러리**: Radix UI + Tailwind CSS - **코드 에디터**: Monaco Editor - **레이아웃**: react-resizable-panels @@ -173,7 +173,7 @@ src/ - **프레임워크**: Tauri 2.0 - **JavaScript 엔진**: Deno Core 0.323 (V8 기반) - **테스팅**: cargo test -- **린팅**: rustfmt + clippy +- **린팅**: rustfmt - **로깅**: tracing ### 모노레포 구조 @@ -181,75 +181,3 @@ src/ - **pnpm 워크스페이스**: Node.js 패키지 관리 - **Cargo 워크스페이스**: Rust 크레이트 관리 - **조건부 CI**: 폴더별 변경사항에 따른 워크플로우 실행 - -## 상태 관리 (Legend State) - -### 기본 사용법 - -```typescript -import { observable } from '@legendapp/state'; -import { useObservable } from '@legendapp/state/react'; - -// 상태 정의 -const state = observable({ - count: 0, - name: 'ExecuteJS' -}); - -// 컴포넌트에서 사용 -function Counter() { - const count = useObservable(state.count); - - return ( -
-

Count: {count}

- -
- ); -} -``` - -### 액션 패턴 - -```typescript -// features/counter/model.ts -export const counterState = observable({ - count: 0, -}); - -export const counterActions = { - increment: () => counterState.count++, - decrement: () => counterState.count--, - reset: () => (counterState.count = 0), -}; -``` - -## UI 컴포넌트 (Radix UI + Tailwind) - -### Radix UI 사용법 - -```typescript -import { Button, Box, Text } from '@radix-ui/themes'; - -function MyComponent() { - return ( - - - Hello World - - - - ); -} -``` - -### Tailwind CSS 클래스 - -- **색상**: `bg-gray-2`, `text-gray-12`, `border-gray-6` -- **간격**: `p-4`, `m-2`, `gap-2` -- **레이아웃**: `flex`, `grid`, `h-full`, `w-full` -- **상태**: `hover:bg-gray-4`, `focus:ring-2` diff --git a/docs/docs/guide/getting-started.mdx b/docs/docs/guide/getting-started.mdx index 9f41b2d..2d2f843 100644 --- a/docs/docs/guide/getting-started.mdx +++ b/docs/docs/guide/getting-started.mdx @@ -44,12 +44,6 @@ ExecuteJS를 사용하여 JavaScript 코드를 안전하게 실행하는 방법 - **저장**: 현재 작성한 코드를 로컬에 저장할 수 있습니다. - **로드**: 이전에 저장한 코드를 불러올 수 있습니다. -### 실행 기록 관리 - -- 모든 실행 결과는 자동으로 기록됩니다. -- 기록을 확인하고 이전 결과를 다시 볼 수 있습니다. -- 필요에 따라 기록을 삭제할 수 있습니다. - ## 프로젝트 구조 ``` diff --git a/docs/docs/guide/live-demo.mdx b/docs/docs/guide/live-demo.mdx index 0a90f97..a0ec104 100644 --- a/docs/docs/guide/live-demo.mdx +++ b/docs/docs/guide/live-demo.mdx @@ -2,175 +2,4 @@ ExecuteJS의 라이브 데모를 통해 JavaScript 실행 기능을 직접 체험해보세요. -## 기본 사용법 - -다음은 ExecuteJS의 기본 기능을 시뮬레이션하는 예제입니다: - -```tsx live -export default function BasicExample() { - const greeting = 'Hello, ExecuteJS!'; - const sum = 10 + 20; - const jsResult = 'JavaScript 실행 시뮬레이션: console.log("Hello from ExecuteJS!");'; - - return ( -
-

ExecuteJS 기본 데모

-

인사: {greeting}

-

덧셈: 10 + 20 = {sum}

-

JavaScript 실행: {jsResult}

-
- ); -} -``` - -## JavaScript 실행 시뮬레이션 - -실제 JavaScript 코드 실행을 시뮬레이션하는 예제입니다: - -```tsx live -import { useState } from 'react'; - -export default function JsExecutionDemo() { - const [code, setCode] = useState('console.log("Hello, ExecuteJS!");'); - const [result, setResult] = useState(''); - - const handleExecute = () => { - // JavaScript 실행 시뮬레이션 - const mockResult = `실행 결과: ${code.length}자 코드가 실행되었습니다.\n실제 실행: ${code}`; - setResult(mockResult); - }; - - return ( -
-

JavaScript 실행 데모

-
-