Browse Source

增加字符串中内置动态js脚本

main
李金 2 months ago
parent
commit
f8f1319e2d
  1. 38
      src/utils/dy_js_exec_test.ts
  2. 85
      src/utils/dynamic_script_executor.ts

38
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)

85
src/utils/dynamic_script_executor.ts

@ -1,3 +1,5 @@
import React from 'react'
type Context = Record<string, any>;
/**
@ -5,13 +7,25 @@ type Context = Record<string, any>;
*/
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<any> {
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<any[]> {
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,

Loading…
Cancel
Save