From f8f1319e2d1ac05d964dbdf5583a07354283b02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=87=91?= Date: Tue, 27 Aug 2024 19:21:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AD=97=E7=AC=A6=E4=B8=B2?= =?UTF-8?q?=E4=B8=AD=E5=86=85=E7=BD=AE=E5=8A=A8=E6=80=81js=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/dy_js_exec_test.ts | 38 ++++++++++++---- src/utils/dynamic_script_executor.ts | 85 ++++++++++++++++++++++++++---------- 2 files changed, 92 insertions(+), 31 deletions(-) diff --git a/src/utils/dy_js_exec_test.ts b/src/utils/dy_js_exec_test.ts index 764a9c7..72495ef 100644 --- a/src/utils/dy_js_exec_test.ts +++ b/src/utils/dy_js_exec_test.ts @@ -1,17 +1,39 @@ // 示例使用 import { DynamicScriptExecutor } from '@/utils/dynamic_script_executor.ts' -const executor = new DynamicScriptExecutor({ +// 示例使用 +const inputString = ` + This is some text. + {{ console.log("Dynamic JS block 1"); }} + More text here. + <% + let x = 10; + let y = 20; + console.log("Dynamic JS block 2: ", x + y); + %> + And some final text. +` + +// 使用默认的 {{ 和 }} 标记 +const executorDefault = new DynamicScriptExecutor({ user: { name: 'Alice', age: 30 }, sayHello: (name: string) => `Hello, ${name}!` }) +// 使用默认标记执行动态JS块 +executorDefault.execute(inputString) + .then(results => console.log('执行结果(默认标记):', results)) + .catch(error => console.error('捕获到的错误:', error)) + +// 使用自定义的 <% 和 %> 标记 +const executorCustom = new DynamicScriptExecutor( + { user: { name: 'Alice', age: 30 }, sayHello: (name: string) => `Hello, ${name}!` }, + '<%', + '%>' +) -// 代码块中有可能抛出异常的代码 -const result = executor.execute(` - console.log(user); - throw new Error('测试错误'); // 故意抛出一个错误 - return sayHello(user.name); -`) +// 使用自定义标记执行动态JS块 +executorCustom.execute(inputString) + .then(results => console.log('执行结果(自定义标记):', results)) + .catch(error => console.error('捕获到的错误:', error)) -result.then(console.log).catch(console.error) diff --git a/src/utils/dynamic_script_executor.ts b/src/utils/dynamic_script_executor.ts index 0b91a0d..d24e745 100644 --- a/src/utils/dynamic_script_executor.ts +++ b/src/utils/dynamic_script_executor.ts @@ -1,3 +1,5 @@ +import React from 'react' + type Context = Record; /** @@ -5,13 +7,25 @@ type Context = Record; */ export class DynamicScriptExecutor { private context: Context + private startDelimiter: string + private endDelimiter: string - constructor(context: Context = {}) { + constructor(context: Context = {}, startDelimiter: string = '{{', endDelimiter: string = '}}') { this.context = context + this.startDelimiter = startDelimiter + this.endDelimiter = endDelimiter + } + + setDelimiters(startDelimiter: string, endDelimiter: string) { + this.startDelimiter = startDelimiter + this.endDelimiter = endDelimiter } setContext(context: Context) { - this.context = context + this.context = { + ...this.context, + ...context + } } // 检测JS代码的语法是否正确 @@ -23,38 +37,62 @@ export class DynamicScriptExecutor { new Function(contextKeys, `return (async () => { ${script} })();`) return null // 语法正确 } catch (error) { - // console.error('代码语法错误:', error) - return error // 语法错误 + console.error('代码语法错误:', error) + return error // 语法错误 } } - async execute(script: string): Promise { - const contextKeys = Object.keys(this.context).join(',') - const contextValues = Object.values(this.context) + // 自动识别并提取动态JS执行块 + extractDynamicJSBlocks(input: string): string[] { + const regex = new RegExp( + `${this.escapeRegExp(this.startDelimiter)}(.*?)${this.escapeRegExp(this.endDelimiter)}`, + 'gs' + ) + + const matches: string[] = [] + let match - // 先检测代码语法 - const err = this.checkSyntax(script) - if (err !== null) { - console.error('检测到代码语法错误,未执行代码。') - throw err + while ((match = regex.exec(input)) !== null) { + matches.push(match[1].trim()) } - // 使用 Function 构造函数创建一个新的异步函数,并在其中执行代码 - const func = new Function(contextKeys, `return (async () => { ${script} })();`) + return matches + } - try { - // 调用函数并传入上下文对象的值 - return await func(...contextValues) - } catch (error) { - this.handleError(error) - throw error + // 执行所有提取的动态JS块 + async execute(input: string): Promise { + const dynamicBlocks = this.extractDynamicJSBlocks(input) + const results: any[] = [] + + for (const script of dynamicBlocks) { + const contextKeys = Object.keys(this.context).join(',') + const contextValues = Object.values(this.context) + + const error = this.checkSyntax(script) + if (error !== null) { + throw error // 抛出异常以便在调用方捕获 + } + + const func = new Function(contextKeys, `return (async () => { ${script} })();`) + + try { + results.push(await func(...contextValues)) + } catch (error) { + this.handleError(error) + throw error + } } + + return results } private handleError(error: any) { - // 在这里处理错误,例如显示错误提示、日志记录、发送错误报告等 - //alert(`执行代码时发生错误: ${error.message}`) - console.error(`执行代码时发生错误: ${error.message}`) + console.log(`执行代码时发生错误: ${error.message}`) + } + + // 转义正则表达式中的特殊字符 + private escapeRegExp(string: string): string { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') } } @@ -71,6 +109,7 @@ export const defaultExecutor = new DynamicScriptExecutor({ clearInterval, fetch, location, + React, // document, FormData, URLSearchParams,