| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /**
- * 语句:set 设置变量 + 变量与值解析(原 value-resolver:extractVarName、replaceVariablesInString、resolveValue、parseValue、时间/延迟)
- */
- const { assertStrictKeys } = require('../action-schema.js')
- const types = ['set']
- function extractVarName(varName) {
- if (typeof varName === 'string' && varName.startsWith('{') && varName.endsWith('}')) {
- return varName.slice(1, -1)
- }
- return varName
- }
- function replaceVariablesInString(str, context) {
- if (typeof str !== 'string') return str
- const replacer = (match, varName) => {
- const varValue = context[varName]
- if (varValue === undefined || varValue === null || varValue === '') return ''
- if (varValue === 'undefined' || varValue === 'null') return ''
- if (typeof varValue === 'string') {
- try {
- const parsed = JSON.parse(varValue)
- if (Array.isArray(parsed)) return parsed.length === 0 ? '' : varValue
- } catch (e) {}
- }
- if (Array.isArray(varValue) || (typeof varValue === 'object' && varValue !== null)) {
- try {
- return JSON.stringify(varValue)
- } catch (e) {
- return String(varValue)
- }
- }
- return String(varValue)
- }
- const doubleBracePattern = /\{\{([\w-]+)\}\}/g
- const singleBracePattern = /\{([\w-]+)\}/g
- return str.replace(doubleBracePattern, replacer).replace(singleBracePattern, replacer)
- }
- function resolveValue(value, context) {
- if (typeof value === 'string' && value.startsWith('{') && value.endsWith('}')) {
- const varName = value.slice(1, -1)
- return context[varName] !== undefined ? context[varName] : value
- }
- if (Array.isArray(value)) {
- return value.map(item => resolveValue(item, context))
- }
- if (typeof value === 'object' && value !== null) {
- const resolved = {}
- for (const key in value) {
- resolved[key] = resolveValue(value[key], context)
- }
- return resolved
- }
- return value
- }
- function parseTimeString(timeStr) {
- if (!timeStr || typeof timeStr !== 'string' || timeStr.trim() === '') return null
- try {
- const parts = timeStr.trim().split(' ')
- if (parts.length !== 2) return null
- const datePart = parts[0].split('/')
- const timePart = parts[1].split(':')
- if (datePart.length !== 3 || timePart.length !== 2) return null
- const date = new Date(
- parseInt(datePart[0], 10),
- parseInt(datePart[1], 10) - 1,
- parseInt(datePart[2], 10),
- parseInt(timePart[0], 10),
- parseInt(timePart[1], 10),
- 0, 0
- )
- return isNaN(date.getTime()) ? null : date
- } catch (e) {
- return null
- }
- }
- // 时长单位(毫秒):ms/s/m/h/d/w/mon/月/y;组合如 1y3mon、1h30m、2d
- const DELAY_UNIT_MS = {
- ms: 1,
- s: 1000,
- m: 60 * 1000,
- h: 60 * 60 * 1000,
- d: 24 * 60 * 60 * 1000,
- w: 7 * 24 * 60 * 60 * 1000,
- mon: 30 * 24 * 60 * 60 * 1000,
- '月': 30 * 24 * 60 * 60 * 1000,
- y: 365 * 24 * 60 * 60 * 1000,
- }
- /** 解析时长字符串。单位:ms(毫秒) s(秒) m(分) h(时) d(天) w(周) mon/月(月) y(年),可组合如 1y3mon、7s、1h30m。纯数字按秒处理。 */
- function parseDelayString(delayStr) {
- if (delayStr == null) return 0
- if (typeof delayStr === 'number' && !Number.isNaN(delayStr) && delayStr >= 0) return Math.round(delayStr * 1000)
- if (typeof delayStr !== 'string' || delayStr.trim() === '') return 0
- try {
- const trimmed = String(delayStr).trim()
- // 单位顺序:ms、mon 必须在 m、s 前,避免被拆成 m+s
- const re = /(\d+)\s*(ms|mon|s|m|h|d|w|月|y)/gi
- let total = 0
- let hadMatch = false
- let match
- while ((match = re.exec(trimmed)) !== null) {
- const value = parseInt(match[1], 10)
- const unit = match[2].toLowerCase()
- if (value < 0 || !DELAY_UNIT_MS[unit]) continue
- total += value * DELAY_UNIT_MS[unit]
- hadMatch = true
- }
- if (hadMatch) return total
- // 纯数字视为秒(如 "15" 或变量解析后只剩数字)
- const bare = /^\d+$/.test(trimmed)
- if (bare) return parseInt(trimmed, 10) * 1000
- return 0
- } catch (e) {
- return 0
- }
- }
- function calculateWaitTime(data, delay) {
- return 0
- }
- function parseValue(str) {
- if (typeof str !== 'string') return str
- str = str.trim()
- if (str === 'true') return true
- if (str === 'false') return false
- if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) {
- return str.slice(1, -1).replace(/\\"/g, '"').replace(/\\'/g, "'")
- }
- if (/^-?\d+(\.\d+)?$/.test(str)) return parseFloat(str)
- if (str === 'undefined') return undefined
- return str
- }
- function parse (action, parseContext) {
- const path = parseContext.actionPath || 'set'
- assertStrictKeys(action, ['type', 'variable', 'value'], path)
- if (action.variable === undefined || action.variable === null || action.variable === '') {
- throw new Error(`${path}: set 须提供 variable`)
- }
- const variableContext = parseContext.variableContext || {}
- return {
- type: 'set',
- variable: action.variable,
- value: resolveValue(action.value, variableContext),
- }
- }
- async function execute(action, ctx) {
- const { variableContext, evaluateExpression } = ctx
- if (!action.variable) return { success: true }
- const varName = extractVarName(action.variable)
- let finalValue = action.value
- if (typeof action.value === 'string' && /[+\-*/]/.test(action.value)) {
- finalValue = evaluateExpression(action.value, variableContext)
- } else if (typeof action.value === 'string') {
- const varPattern = /\{([\w-]+)\}/g
- let hasVariables = false
- finalValue = action.value.replace(varPattern, (match, vn) => {
- hasVariables = true
- const val = variableContext[vn]
- return val === undefined || val === null ? match : String(val)
- })
- if (!hasVariables) finalValue = resolveValue(action.value, variableContext)
- } else {
- finalValue = resolveValue(action.value, variableContext)
- }
- variableContext[varName] = finalValue
- return { success: true }
- }
- module.exports = {
- types,
- parse,
- execute,
- extractVarName,
- replaceVariablesInString,
- resolveValue,
- parseTimeString,
- parseDelayString,
- calculateWaitTime,
- parseValue,
- }
|