dasdasd
This commit is contained in:
parent
6d70376a26
commit
beca781934
@ -17,29 +17,96 @@ class BaseAction {
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换配置中的变量
|
||||
* @param {string} value - 包含变量的字符串 (如 "{{account.email}}")
|
||||
* 替换配置中的变量(增强版)
|
||||
*
|
||||
* 支持特性:
|
||||
* - 多数据源:{{account.email}}, {{site.url}}, {{config.timeout}}
|
||||
* - 默认值:{{var|default}}, {{user.name|Guest}}
|
||||
* - 变量不存在时警告
|
||||
*
|
||||
* @param {string} value - 包含变量的字符串
|
||||
* @returns {string} - 替换后的值
|
||||
*/
|
||||
replaceVariables(value) {
|
||||
if (typeof value !== 'string') return value;
|
||||
|
||||
return value.replace(/\{\{(.+?)\}\}/g, (match, path) => {
|
||||
const keys = path.trim().split('.');
|
||||
let result = this.context.data;
|
||||
return value.replace(/\{\{(.+?)\}\}/g, (match, expression) => {
|
||||
// 解析默认值:{{var|default}}
|
||||
const [path, defaultValue] = expression.split('|').map(s => s.trim());
|
||||
|
||||
for (const key of keys) {
|
||||
if (result && typeof result === 'object') {
|
||||
result = result[key];
|
||||
} else {
|
||||
return match; // 无法解析,返回原始值
|
||||
}
|
||||
// 获取变量值
|
||||
const result = this.resolveVariablePath(path);
|
||||
|
||||
// 如果找到值,返回
|
||||
if (result !== undefined && result !== null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result !== undefined ? result : match;
|
||||
// 如果有默认值,使用默认值
|
||||
if (defaultValue !== undefined) {
|
||||
this.log('debug', `变量 "${path}" 不存在,使用默认值: "${defaultValue}"`);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// 变量不存在且无默认值,发出警告
|
||||
this.log('warn', `⚠️ 变量 "${path}" 不存在,返回原始值: ${match}`);
|
||||
return match;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析变量路径,支持多个数据源
|
||||
* @param {string} path - 变量路径,如 "account.email" 或 "site.url"
|
||||
* @returns {*} - 解析后的值
|
||||
*/
|
||||
resolveVariablePath(path) {
|
||||
const keys = path.split('.');
|
||||
const rootKey = keys[0];
|
||||
|
||||
// 确定数据源
|
||||
let dataSource;
|
||||
let startIndex = 1; // 从第二个key开始
|
||||
|
||||
switch (rootKey) {
|
||||
case 'site':
|
||||
// {{site.url}} -> context.siteConfig.url
|
||||
dataSource = this.context.siteConfig;
|
||||
break;
|
||||
|
||||
case 'config':
|
||||
// {{config.timeout}} -> context.config
|
||||
dataSource = this.context.config;
|
||||
break;
|
||||
|
||||
case 'env':
|
||||
// {{env.API_KEY}} -> process.env
|
||||
dataSource = process.env;
|
||||
break;
|
||||
|
||||
default:
|
||||
// 默认从 context.data 读取
|
||||
// {{account.email}} -> context.data.account.email
|
||||
dataSource = this.context.data;
|
||||
startIndex = 0; // 从第一个key开始
|
||||
}
|
||||
|
||||
if (!dataSource) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 遍历路径获取值
|
||||
let result = dataSource;
|
||||
for (let i = startIndex; i < keys.length; i++) {
|
||||
if (result && typeof result === 'object') {
|
||||
result = result[keys[i]];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志
|
||||
*/
|
||||
|
||||
@ -106,6 +106,9 @@ class ConfigValidator {
|
||||
}
|
||||
});
|
||||
|
||||
// 类型检查
|
||||
errors.push(...this.validateFieldTypes(step, stepLabel));
|
||||
|
||||
// 检查未知字段(警告)
|
||||
const allFields = [...schema.required, ...schema.optional, 'action'];
|
||||
Object.keys(step).forEach(field => {
|
||||
@ -135,6 +138,47 @@ class ConfigValidator {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型检查
|
||||
*/
|
||||
validateFieldTypes(step, stepLabel) {
|
||||
const errors = [];
|
||||
|
||||
// fillForm 的 fields 应该是对象
|
||||
if (step.action === 'fillForm' && step.fields) {
|
||||
if (typeof step.fields !== 'object' || Array.isArray(step.fields)) {
|
||||
errors.push(`${stepLabel}: fields 必须是对象类型`);
|
||||
}
|
||||
}
|
||||
|
||||
// 数字类型字段检查
|
||||
const numberFields = ['timeout', 'maxRetries', 'retryDelay', 'duration', 'totalTimeout', 'pollInterval'];
|
||||
numberFields.forEach(field => {
|
||||
if (step[field] !== undefined && typeof step[field] !== 'number') {
|
||||
errors.push(`${stepLabel}: ${field} 必须是数字类型,当前为 ${typeof step[field]}`);
|
||||
}
|
||||
});
|
||||
|
||||
// 布尔类型字段检查
|
||||
const booleanFields = ['humanLike', 'optional', 'waitForEnabled'];
|
||||
booleanFields.forEach(field => {
|
||||
if (step[field] !== undefined && typeof step[field] !== 'boolean') {
|
||||
errors.push(`${stepLabel}: ${field} 必须是布尔类型,当前为 ${typeof step[field]}`);
|
||||
}
|
||||
});
|
||||
|
||||
// 数组类型字段检查
|
||||
if (step.steps && !Array.isArray(step.steps)) {
|
||||
errors.push(`${stepLabel}: steps 必须是数组类型`);
|
||||
}
|
||||
|
||||
if (step.verifyElements && !Array.isArray(step.verifyElements)) {
|
||||
errors.push(`${stepLabel}: verifyElements 必须是数组类型`);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证并打印结果
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user