set-parser.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /**
  2. * 语句:set 设置变量 + 变量与值解析(原 value-resolver:extractVarName、replaceVariablesInString、resolveValue、parseValue、时间/延迟)
  3. */
  4. const types = ['set']
  5. function extractVarName(varName) {
  6. if (typeof varName === 'string' && varName.startsWith('{') && varName.endsWith('}')) {
  7. return varName.slice(1, -1)
  8. }
  9. return varName
  10. }
  11. function replaceVariablesInString(str, context) {
  12. if (typeof str !== 'string') return str
  13. const replacer = (match, varName) => {
  14. const varValue = context[varName]
  15. if (varValue === undefined || varValue === null || varValue === '') return ''
  16. if (varValue === 'undefined' || varValue === 'null') return ''
  17. if (typeof varValue === 'string') {
  18. try {
  19. const parsed = JSON.parse(varValue)
  20. if (Array.isArray(parsed)) return parsed.length === 0 ? '' : varValue
  21. } catch (e) {}
  22. }
  23. if (Array.isArray(varValue) || (typeof varValue === 'object' && varValue !== null)) {
  24. try {
  25. return JSON.stringify(varValue)
  26. } catch (e) {
  27. return String(varValue)
  28. }
  29. }
  30. return String(varValue)
  31. }
  32. const doubleBracePattern = /\{\{([\w-]+)\}\}/g
  33. const singleBracePattern = /\{([\w-]+)\}/g
  34. return str.replace(doubleBracePattern, replacer).replace(singleBracePattern, replacer)
  35. }
  36. function resolveValue(value, context) {
  37. if (typeof value === 'string' && value.startsWith('{') && value.endsWith('}')) {
  38. const varName = value.slice(1, -1)
  39. return context[varName] !== undefined ? context[varName] : value
  40. }
  41. if (Array.isArray(value)) {
  42. return value.map(item => resolveValue(item, context))
  43. }
  44. if (typeof value === 'object' && value !== null) {
  45. const resolved = {}
  46. for (const key in value) {
  47. resolved[key] = resolveValue(value[key], context)
  48. }
  49. return resolved
  50. }
  51. return value
  52. }
  53. function parseTimeString(timeStr) {
  54. if (!timeStr || typeof timeStr !== 'string' || timeStr.trim() === '') return null
  55. try {
  56. const parts = timeStr.trim().split(' ')
  57. if (parts.length !== 2) return null
  58. const datePart = parts[0].split('/')
  59. const timePart = parts[1].split(':')
  60. if (datePart.length !== 3 || timePart.length !== 2) return null
  61. const date = new Date(
  62. parseInt(datePart[0], 10),
  63. parseInt(datePart[1], 10) - 1,
  64. parseInt(datePart[2], 10),
  65. parseInt(timePart[0], 10),
  66. parseInt(timePart[1], 10),
  67. 0, 0
  68. )
  69. return isNaN(date.getTime()) ? null : date
  70. } catch (e) {
  71. return null
  72. }
  73. }
  74. // 时长单位(毫秒):ms/s/m/h/d/w/mon/月/y;组合如 1y3mon、1h30m、2d
  75. const DELAY_UNIT_MS = {
  76. ms: 1,
  77. s: 1000,
  78. m: 60 * 1000,
  79. h: 60 * 60 * 1000,
  80. d: 24 * 60 * 60 * 1000,
  81. w: 7 * 24 * 60 * 60 * 1000,
  82. mon: 30 * 24 * 60 * 60 * 1000,
  83. '月': 30 * 24 * 60 * 60 * 1000,
  84. y: 365 * 24 * 60 * 60 * 1000,
  85. }
  86. /** 解析时长字符串。单位:ms(毫秒) s(秒) m(分) h(时) d(天) w(周) mon/月(月) y(年),可组合如 1y3mon、7s、1h30m。纯数字按秒处理。 */
  87. function parseDelayString(delayStr) {
  88. if (delayStr == null) return 0
  89. if (typeof delayStr === 'number' && !Number.isNaN(delayStr) && delayStr >= 0) return Math.round(delayStr * 1000)
  90. if (typeof delayStr !== 'string' || delayStr.trim() === '') return 0
  91. try {
  92. const trimmed = String(delayStr).trim()
  93. // 单位顺序:ms、mon 必须在 m、s 前,避免被拆成 m+s
  94. const re = /(\d+)\s*(ms|mon|s|m|h|d|w|月|y)/gi
  95. let total = 0
  96. let hadMatch = false
  97. let match
  98. while ((match = re.exec(trimmed)) !== null) {
  99. const value = parseInt(match[1], 10)
  100. const unit = match[2].toLowerCase()
  101. if (value < 0 || !DELAY_UNIT_MS[unit]) continue
  102. total += value * DELAY_UNIT_MS[unit]
  103. hadMatch = true
  104. }
  105. if (hadMatch) return total
  106. // 纯数字视为秒(如 "15" 或变量解析后只剩数字)
  107. const bare = /^\d+$/.test(trimmed)
  108. if (bare) return parseInt(trimmed, 10) * 1000
  109. return 0
  110. } catch (e) {
  111. return 0
  112. }
  113. }
  114. function calculateWaitTime(data, delay) {
  115. return 0
  116. }
  117. function parseValue(str) {
  118. if (typeof str !== 'string') return str
  119. str = str.trim()
  120. if (str === 'true') return true
  121. if (str === 'false') return false
  122. if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) {
  123. return str.slice(1, -1).replace(/\\"/g, '"').replace(/\\'/g, "'")
  124. }
  125. if (/^-?\d+(\.\d+)?$/.test(str)) return parseFloat(str)
  126. if (str === 'undefined') return undefined
  127. return str
  128. }
  129. function parse(action, parseContext) {
  130. const variableContext = parseContext.variableContext || {}
  131. const parsed = {
  132. type: 'set',
  133. variable: action.variable,
  134. value: resolveValue(action.value, variableContext),
  135. }
  136. return Object.assign({}, action, parsed)
  137. }
  138. async function execute(action, ctx) {
  139. const { variableContext, evaluateExpression } = ctx
  140. if (!action.variable) return { success: true }
  141. const varName = extractVarName(action.variable)
  142. let finalValue = action.value
  143. if (typeof action.value === 'string' && /[+\-*/]/.test(action.value)) {
  144. finalValue = evaluateExpression(action.value, variableContext)
  145. } else if (typeof action.value === 'string') {
  146. const varPattern = /\{([\w-]+)\}/g
  147. let hasVariables = false
  148. finalValue = action.value.replace(varPattern, (match, vn) => {
  149. hasVariables = true
  150. const val = variableContext[vn]
  151. return val === undefined || val === null ? match : String(val)
  152. })
  153. if (!hasVariables) finalValue = resolveValue(action.value, variableContext)
  154. } else {
  155. finalValue = resolveValue(action.value, variableContext)
  156. }
  157. variableContext[varName] = finalValue
  158. return { success: true }
  159. }
  160. module.exports = {
  161. types,
  162. parse,
  163. execute,
  164. extractVarName,
  165. replaceVariablesInString,
  166. resolveValue,
  167. parseTimeString,
  168. parseDelayString,
  169. calculateWaitTime,
  170. parseValue,
  171. }