Files
iqudo-top1/internal/scriptkit/validator.go
Eric 1549169735@qq.com da3f16e6db update
2026-09-13 20:08:13 +08:00

137 lines
5.2 KiB
Go

package scriptkit
import (
"fmt"
"regexp"
)
var keyPattern = regexp.MustCompile(`^[A-Za-z][A-Za-z0-9_]*$`)
var allowedScriptTypes = map[string]bool{
"confirm": true, "info": true, "choice": true, "screen": true, "template": true, "fallback": true, "message": true,
}
var allowedEffects = map[string]bool{
"set": true, "add": true, "subtract": true, "zero": true,
}
var allowedRelationTypes = map[string]bool{
"contributes_to": true, "requires": true, "excludes": true,
}
// ValidatePackageInput checks a package document before saving.
func ValidatePackageInput(input PackageInput) error {
if input.Name == "" {
return fmt.Errorf("话术包缺少名称")
}
if !keyPattern.MatchString(input.StartStageKey) {
return fmt.Errorf("开始阶段标识格式不正确")
}
dimensionKeys := map[string]bool{}
valueKeys := map[string]bool{}
stageKeys := map[string]bool{}
scriptKeys := map[string]bool{}
valueDimension := map[string]string{}
for _, dimension := range input.Dimensions {
if !keyPattern.MatchString(dimension.DimKey) || dimensionKeys[dimension.DimKey] {
return fmt.Errorf("维度标识必须唯一且格式正确")
}
if dimension.Name == "" {
return fmt.Errorf("维度 %s 缺少名称", dimension.DimKey)
}
dimensionKeys[dimension.DimKey] = true
for _, value := range dimension.Values {
if !keyPattern.MatchString(value.ValueKey) || valueKeys[value.ValueKey] {
return fmt.Errorf("维度值标识必须唯一且格式正确")
}
if value.Name == "" {
return fmt.Errorf("维度值 %s 缺少名称", value.ValueKey)
}
valueKeys[value.ValueKey] = true
valueDimension[value.ValueKey] = dimension.DimKey
}
}
for _, stage := range input.Stages {
if !keyPattern.MatchString(stage.StageKey) || stageKeys[stage.StageKey] {
return fmt.Errorf("阶段标识必须唯一且格式正确")
}
if stage.Name == "" {
return fmt.Errorf("阶段 %s 缺少名称", stage.StageKey)
}
if stage.PrimaryDimensionKey != "" && !dimensionKeys[stage.PrimaryDimensionKey] {
return fmt.Errorf("阶段 %s 的主维度不存在", stage.StageKey)
}
stageKeys[stage.StageKey] = true
for _, script := range stage.Scripts {
if !keyPattern.MatchString(script.ScriptKey) || scriptKeys[script.ScriptKey] {
return fmt.Errorf("话术标识必须唯一且格式正确")
}
if script.Name == "" {
return fmt.Errorf("话术 %s 缺少名称", script.ScriptKey)
}
if !allowedScriptTypes[script.ScriptType] {
return fmt.Errorf("话术 %s 的类型 %s 不支持", script.ScriptKey, script.ScriptType)
}
if script.DimensionValueKey != "" && !valueKeys[script.DimensionValueKey] {
return fmt.Errorf("话术 %s 关联的维度值不存在", script.ScriptKey)
}
if script.ScriptType == "confirm" && script.DimensionValueKey == "" {
return fmt.Errorf("确认性话术 %s 必须关联维度值", script.ScriptKey)
}
if script.ShowThreshold < 0 || script.ConfirmThreshold < 0 {
return fmt.Errorf("话术 %s 的阈值不能为负数", script.ScriptKey)
}
if script.ConfirmThreshold > script.ShowThreshold && script.ShowThreshold > 0 {
return fmt.Errorf("话术 %s 的确认阈值不能大于显示阈值", script.ScriptKey)
}
scriptKeys[script.ScriptKey] = true
optionKeys := map[string]bool{}
for _, option := range script.Options {
if !keyPattern.MatchString(option.OptionKey) || optionKeys[option.OptionKey] {
return fmt.Errorf("话术 %s 的选项标识必须唯一且格式正确", script.ScriptKey)
}
if option.Label == "" {
return fmt.Errorf("话术 %s 的选项 %s 缺少文案", script.ScriptKey, option.OptionKey)
}
if option.TargetDimensionValueKey != "" && !valueKeys[option.TargetDimensionValueKey] {
return fmt.Errorf("话术 %s 选项 %s 关联的维度值不存在", script.ScriptKey, option.OptionKey)
}
if !allowedEffects[option.Effect] {
return fmt.Errorf("话术 %s 选项 %s 的效果 %s 不支持", script.ScriptKey, option.OptionKey, option.Effect)
}
if option.EffectValue < 0 {
return fmt.Errorf("话术 %s 选项 %s 的效果值不能为负数", script.ScriptKey, option.OptionKey)
}
optionKeys[option.OptionKey] = true
}
}
}
if !stageKeys[input.StartStageKey] {
return fmt.Errorf("开始阶段 %s 不存在", input.StartStageKey)
}
for _, linkage := range input.Linkages {
if !valueKeys[linkage.FromDimensionValueKey] || !valueKeys[linkage.ToDimensionValueKey] {
return fmt.Errorf("维度联动引用了不存在的维度值")
}
if !allowedRelationTypes[linkage.RelationType] {
return fmt.Errorf("联动关系 %s 不支持", linkage.RelationType)
}
if linkage.Contribution <= 0 {
return fmt.Errorf("联动贡献值必须为正数")
}
}
for _, adapter := range input.Adapters {
if adapter.SourceField == "" || adapter.MatchValue == "" {
return fmt.Errorf("入场适配规则缺少来源字段或匹配值")
}
if !valueKeys[adapter.TargetDimensionValueKey] {
return fmt.Errorf("入场适配规则 %s=%s 关联的维度值不存在", adapter.SourceField, adapter.MatchValue)
}
if adapter.Weight <= 0 {
return fmt.Errorf("入场适配规则 %s=%s 的权重必须为正数", adapter.SourceField, adapter.MatchValue)
}
}
_ = valueDimension
return nil
}