You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.1 KiB
134 lines
3.1 KiB
import React from 'react'
|
|
|
|
type Context = Record<string, any>;
|
|
|
|
/**
|
|
* 动态执行 JavaScript 脚本的工具类
|
|
*/
|
|
export class DynamicScriptExecutor {
|
|
private context: Context
|
|
private startDelimiter: string
|
|
private endDelimiter: string
|
|
|
|
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 = {
|
|
...this.context,
|
|
...context
|
|
}
|
|
}
|
|
|
|
// 检测JS代码的语法是否正确
|
|
checkSyntax(script: string) {
|
|
const contextKeys = Object.keys(this.context).join(',')
|
|
|
|
try {
|
|
// 尝试创建一个新的函数,如果代码有语法错误,这里会抛出异常
|
|
new Function(contextKeys, `return (async () => { ${script} })();`)
|
|
return null // 语法正确
|
|
} catch (error) {
|
|
console.error('代码语法错误:', error)
|
|
return error // 语法错误
|
|
}
|
|
}
|
|
|
|
// 自动识别并提取动态JS执行块
|
|
extractDynamicJSBlocks(input: string): string[] {
|
|
const regex = new RegExp(
|
|
`${this.escapeRegExp(this.startDelimiter)}(.*?)${this.escapeRegExp(this.endDelimiter)}`,
|
|
'gs'
|
|
)
|
|
|
|
const matches: string[] = []
|
|
let match
|
|
|
|
while ((match = regex.exec(input)) !== null) {
|
|
matches.push(match[1].trim())
|
|
}
|
|
|
|
return matches
|
|
}
|
|
|
|
// 执行所有提取的动态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) {
|
|
console.log(`执行代码时发生错误: ${error.message}`)
|
|
}
|
|
|
|
// 转义正则表达式中的特殊字符
|
|
private escapeRegExp(string: string): string {
|
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
}
|
|
}
|
|
|
|
// 创建一个默认的执行器实例
|
|
export const defaultExecutor = new DynamicScriptExecutor({
|
|
|
|
// 系统内置的一些全局对象
|
|
|
|
// 全局对象
|
|
console,
|
|
setTimeout,
|
|
setInterval,
|
|
clearTimeout,
|
|
clearInterval,
|
|
fetch,
|
|
location,
|
|
React,
|
|
// document,
|
|
FormData,
|
|
URLSearchParams,
|
|
Headers,
|
|
Request,
|
|
Response,
|
|
Blob,
|
|
FileReader,
|
|
WebSocket,
|
|
EventSource,
|
|
localStorage,
|
|
sessionStorage,
|
|
indexedDB,
|
|
crypto,
|
|
performance,
|
|
navigator,
|
|
history,
|
|
screen,
|
|
alert,
|
|
confirm,
|
|
prompt,
|
|
})
|