| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- // EasyFlow 编译器 - 工作流任务解析和执行器(主机,单文件 ≤500 行)
- // ========== 入口说明:外部通过 require 本模块后,使用下方 module.exports 导出的 5 个方法作为调用入口 ==========
- const path = require('path')
- // --- 配置(原 compiler-config.js 合并到此)---
- const projectRoot = path.resolve(__dirname, '..', '..')
- const funcDir = path.join(__dirname, 'fun')
- const adbInteractPath = path.join(projectRoot, 'nodejs', 'adb', 'adb-interact.js')
- const DEFAULT_STEP_INTERVAL = 1000
- const DEFAULT_SCROLL_DISTANCE = 100
- const compilerConfig = { projectRoot, funcDir, adbInteractPath, DEFAULT_STEP_INTERVAL, DEFAULT_SCROLL_DISTANCE }
- // --- 依赖 ---
- const setParser = require('./components/actions/set-parser.js')
- const expressionEvaluator = require('./components/expression-evaluator.js')
- const runtimeApi = require('./components/runtime-api.js')
- const workflowJsonParser = require('./components/workflow-json-parser.js')
- const sequenceRunner = require('./components/sequence-runner.js')
- const actions = require('./components/actions/fun-parser.js')
- // --- 功能模块(fun 目录)与运行时 API ---
- const { matchImageAndGetCoordinate } = require('./fun/img-center-point-location.js')
- const { readTextFile } = require('./fun/read-txt.js')
- const { writeTextFile } = require('./fun/save-txt.js')
- const electronAPI = runtimeApi.createElectronAPI({ matchImageAndGetCoordinate, readTextFile, writeTextFile }, compilerConfig)
- // --- 共享状态(变量上下文、步骤计数、当前工作流目录等)---
- const state = {
- variableContext: {},
- variableContextInitialized: false,
- globalStepCounter: 0,
- currentWorkflowFolderPath: null,
- }
- // --- 从各组件抽出的工具方法(供本文件与 ctx 使用)---
- const extractVarName = setParser.extractVarName
- const replaceVariablesInString = setParser.replaceVariablesInString
- const resolveValue = setParser.resolveValue
- const parseDelayString = setParser.parseDelayString
- const calculateWaitTime = setParser.calculateWaitTime
- const evaluateCondition = expressionEvaluator.evaluateCondition
- const evaluateExpression = expressionEvaluator.evaluateExpression
- const getActionName = workflowJsonParser.getActionName
- // --- 日志与变量输出 ---
- async function logMessage(message, folderPath = null) {
- try {
- const targetFolderPath = folderPath || state.currentWorkflowFolderPath
- if (targetFolderPath && electronAPI.appendLog) await electronAPI.appendLog(targetFolderPath, message)
- } catch (err) {}
- }
- async function logOutVars(action, variableContext, folderPath = null) {
- if (!action.outVars || !Array.isArray(action.outVars) || action.outVars.length === 0) return
- const outVarsInfo = action.outVars.map((varName) => {
- const varNameClean = extractVarName(varName)
- const value = variableContext[varNameClean]
- let displayValue = value
- if (typeof value === 'string' && value.length > 100) displayValue = value.substring(0, 100) + '...'
- return `${varNameClean}: ${JSON.stringify(displayValue)}`
- })
- }
- // --- 对外入口 1:解析整份工作流 ---
- function parseWorkflow(workflow) {
- const loaderState = {
- variableContext: state.variableContext,
- getInitialized: () => state.variableContextInitialized,
- setInitialized: (v) => { state.variableContextInitialized = v },
- }
- return workflowJsonParser.parseWorkflow(workflow, loaderState)
- }
- // --- 对外入口 2:仅解析动作列表 ---
- function parseActions(actions) {
- const loaderState = {
- variableContext: state.variableContext,
- getInitialized: () => state.variableContextInitialized,
- setInitialized: () => {},
- }
- return workflowJsonParser.parseActions(actions, loaderState)
- }
- // --- 对外入口 3:执行单条动作 ---
- async function executeAction(action, device, folderPath, resolution) {
- const ctx = {
- variableContext: state.variableContext,
- compilerConfig,
- electronAPI,
- extractVarName,
- replaceVariablesInString,
- resolveValue,
- evaluateCondition,
- evaluateExpression,
- getActionName,
- logMessage,
- logOutVars,
- parseDelayString,
- calculateWaitTime,
- DEFAULT_SCROLL_DISTANCE,
- registry: workflowJsonParser.registry,
- executeAction: workflowJsonParser.executeAction,
- }
- try {
- return await actions.runAction(action, device, folderPath, resolution, ctx)
- } catch (error) {
- const now = new Date()
- const timeStr = `${now.getFullYear()}/${String(now.getMonth() + 1).padStart(2, '0')}/${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`
- const errorMsg = `[错误] 操作执行失败: ${error.message} [系统时间: ${timeStr}]`
- await logMessage(errorMsg, folderPath).catch(() => {})
- return { success: false, error: error.message }
- }
- }
- // --- 对外入口 4:按顺序执行动作序列(含 schedule/if/for/while 等)---
- async function executeActionSequence(actions, device, folderPath, resolution, stepInterval = DEFAULT_STEP_INTERVAL, onStepComplete = null, shouldStop = null, depth = 0) {
- const ctx = {
- executeAction,
- logMessage,
- evaluateCondition,
- getActionName,
- parseDelayString,
- calculateWaitTime,
- state,
- DEFAULT_STEP_INTERVAL,
- }
- return sequenceRunner.executeActionSequence(actions, device, folderPath, resolution, stepInterval, onStepComplete, shouldStop, depth, ctx)
- }
- // --- 编译/执行入口:对外暴露的 API ---
- module.exports = {
- parseWorkflow,
- parseActions,
- executeAction,
- executeActionSequence,
- }
|