Переглянути джерело

调整表达式执行方式用NCalc

lichunlei 4 місяців тому
батько
коміт
d03f9273d9
4 змінених файлів з 118 додано та 22 видалено
  1. 1 0
      OmegaMake.csproj
  2. 6 6
      Task/MakeHelper.cs
  3. 21 15
      Util/Maker.cs
  4. 90 1
      Util/Utils.cs

+ 1 - 0
OmegaMake.csproj

@@ -38,6 +38,7 @@
     <PackageReference Include="nacos-sdk-csharp.Extensions.Configuration" Version="1.3.10" />
     <PackageReference Include="nacos-sdk-csharp.IniParser" Version="1.3.10" />
     <PackageReference Include="nacos-sdk-csharp.YamlParser" Version="1.3.10" />
+    <PackageReference Include="NCalc" Version="1.3.8" />
     <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
     <PackageReference Include="NLog" Version="5.2.8" />
     <PackageReference Include="Npgsql" Version="8.0.3" />

+ 6 - 6
Task/MakeHelper.cs

@@ -29,7 +29,7 @@ namespace Tasks
             }
         }
 
-        public async void DoQueue(string content)
+        public void DoQueue(string content)
         {
             try
             {
@@ -39,10 +39,10 @@ namespace Tasks
                 string requestId = jsonObj["requestId"].ToString();
                 //模板文件路径
                 string modePath = jsonObj["modePath"].ToString();
-                if(modePath.Contains("controller"))
-                {
-                    string packageName = "123123123";
-                }
+                // if(modePath.Contains("controller"))
+                // {
+                //     string packageName = "123123123";
+                // }
                 //附加数据,原样返回
                 string attach = jsonObj["attach"].ToString();
                 //读取模板文件内容
@@ -53,7 +53,7 @@ namespace Tasks
                 string templateString = template.templateContent;
                 templateString = HttpUtility.UrlDecode(templateString);
                 //解析模板内容
-                string resultString = await Util.Maker.StartMake(jsonObj["data"], templateString);
+                string resultString = Util.Maker.StartMake(jsonObj["data"], templateString);
                 resultString = Util.Maker.replaceKeyToValue(jsonObj["data"], resultString);
                 //生成文件
                 string path = template.makePath.Substring(0, template.makePath.LastIndexOf("/") + 1);

+ 21 - 15
Util/Maker.cs

@@ -3,6 +3,7 @@ using System.Text.RegularExpressions;
 using Common;
 using LitJson;
 using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
 
 namespace Util
 {
@@ -10,7 +11,7 @@ namespace Util
     {
         
         #region 读取模版数据,替换对应的标签内容
-        public static async Task<string> StartMake(JsonData jsonObj, string templateString)
+        public static string StartMake(JsonData jsonObj, string templateString)
         {
             foreach (string key in jsonObj.Keys)
             {
@@ -20,12 +21,12 @@ namespace Util
                     if (obj.IsArray) //如果是数组
                     {
                         //匹配循环带loop循环标记的内容
-                        templateString = await makeArrayAsync(obj, templateString, key);
+                        templateString = makeArrayAsync(obj, templateString, key);
                     }
                     else if (obj.IsObject) //如果是单个对象
                     {
                         //匹配循环带item单个对象标记的内容
-                        templateString = await makeObjectAsync(obj, templateString, key);
+                        templateString = makeObjectAsync(obj, templateString, key);
                     }
                     else //否则当数值处理
                     {
@@ -37,11 +38,11 @@ namespace Util
                     templateString = templateString.Replace("<<ym:" + key + ">>", "");
                 }
             }
-            templateString = await PublicMakeAsync(templateString);
+            templateString = PublicMake(templateString);
             return templateString;
         }
         
-        public static async Task<string> makeArrayAsync(JsonData jsonObj, string templateString, string key)
+        public static string makeArrayAsync(JsonData jsonObj, string templateString, string key)
         { 
             MatchCollection mc = Regex.Matches(templateString, "<<ym-loop:" + key + ".*?>>[\\s\\S]*?<</ym-loop:" + key + ">>");
             foreach (Match m in mc)
@@ -90,11 +91,11 @@ namespace Util
                             {
                                 if (itemObj.IsArray)
                                 {
-                                    itemString = await makeArrayAsync(itemObj, itemString, itemKey);
+                                    itemString = makeArrayAsync(itemObj, itemString, itemKey);
                                 }
                                 else if (itemObj.IsObject)
                                 {
-                                    itemString = await makeObjectAsync(itemObj, itemString, itemKey);
+                                    itemString = makeObjectAsync(itemObj, itemString, itemKey);
                                 }
                                 else
                                 {
@@ -104,11 +105,13 @@ namespace Util
                             else
                             {
                                 itemString = itemString.Replace("<<" + itemKey + ">>", "");
+                                itemString = Regex.Replace(itemString, "<<ym-loop:" + key + ".*?>>[\\s\\S]*?<</ym-loop:" + key + ">>", "");
+                                itemString = Regex.Replace(itemString, "<<ym-item:" + key + ".*?>>[\\s\\S]*?<</ym-item:" + key + ">>", "");
                             }
                         }
                         listString += itemString;
                     }
-                    listString = await PublicMakeAsync(listString);
+                    listString = PublicMake(listString);
                     //过滤两头的符号
                     if (removeString.Length > 0)
                     {
@@ -130,7 +133,7 @@ namespace Util
             return templateString;
         }
 
-        public static async Task<string> makeObjectAsync(JsonData jsonObj, string templateString, string key)
+        public static string makeObjectAsync(JsonData jsonObj, string templateString, string key)
         {
             MatchCollection mc = Regex.Matches(templateString, "<<ym-item:" + key + ".*?>>[\\s\\S]*?<</ym-item:" + key + ">>");
             foreach (Match m in mc)
@@ -152,11 +155,11 @@ namespace Util
                         {
                             if (itemObj.IsArray)
                             {
-                                itemString = await makeArrayAsync(itemObj, itemString, itemKey);
+                                itemString = makeArrayAsync(itemObj, itemString, itemKey);
                             }
                             else if (itemObj.IsObject)
                             {
-                                itemString = await makeObjectAsync(itemObj, itemString, itemKey);
+                                itemString = makeObjectAsync(itemObj, itemString, itemKey);
                             }
                             else
                             {
@@ -166,6 +169,8 @@ namespace Util
                         else
                         {
                             itemString = itemString.Replace("<<" + itemKey + ">>", "");
+                            itemString = Regex.Replace(itemString, "<<ym-loop:" + key + ".*?>>[\\s\\S]*?<</ym-loop:" + key + ">>", "");
+                            itemString = Regex.Replace(itemString, "<<ym-item:" + key + ".*?>>[\\s\\S]*?<</ym-item:" + key + ">>", "");
                         }
                     }
                     listString += itemString;
@@ -205,7 +210,7 @@ namespace Util
         #endregion
 
         #region 公共标签处理
-        public static async Task<string> PublicMakeAsync(string content)
+        public static string PublicMake(string content)
         {
             MatchCollection mc = Regex.Matches(content, "<<ym-if:.*?>>[\\s\\S]*?<</ym-if>>");
             foreach (Match m in mc)
@@ -224,12 +229,13 @@ namespace Util
                         elseValue = valueData[1];
                     }
                     string condition = headValue.Substring(8, headValue.Length - 10);
-                    condition = condition.Replace("isEmpty", "string.IsNullOrEmpty");
-                    condition = condition.Replace(".start(", ".StartsWith(");
+                    condition = condition.Replace("isEmpty", "IsNullOrEmpty");
+                    condition = condition.Replace("start(", "StartsWith(");
                     condition = condition.Replace("True", "true");
                     condition = condition.Replace("False", "false");
+                    condition = condition.Replace("\"", "'");
                     // Console.WriteLine(condition);
-                    bool result = await CSharpScript.EvaluateAsync<bool>(condition);
+                    bool result = Utils.EvaluateBoolean(condition);
                     content = content.Replace(matchValue, result ? resultValue : elseValue);
                 }
             }

+ 90 - 1
Util/Utils.cs

@@ -1,4 +1,6 @@
-public class Utils
+using NCalc;
+
+public class Utils
 {
     
     #region 打控制台日志
@@ -10,5 +12,92 @@
 
     #endregion
 
+    /// <summary>
+    /// 解析布尔表达式,返回 true/false
+    /// 支持的表达式示例:"10 > 5", "a == b", "(1+2) < 10 && 3 != 4", "true || false"
+    /// </summary>
+    /// <param name="booleanExpression">布尔表达式字符串</param>
+    /// <param name="parameters">可选:表达式中的变量参数(如 a=10, b=5)</param>
+    /// <returns>表达式的布尔结果</returns>
+    public static bool EvaluateBoolean(string booleanExpression, Dictionary<string, object> parameters = null)
+    {
+        try
+        {
+            // 创建表达式对象
+            var expr = new Expression(booleanExpression);
+
+            // 2. 【强制绑定】直接绑定函数事件(不抽离,避免绑定失效)
+            expr.EvaluateFunction += OnEvaluateFunction;
+
+            // 注入变量参数(如果有)
+            if (parameters != null && parameters.Count > 0)
+            {
+                foreach (var param in parameters)
+                {
+                    expr.Parameters[param.Key] = param.Value;
+                }
+            }
+
+            // 执行表达式并转换为布尔值
+            var result = expr.Evaluate();
+            return Convert.ToBoolean(result);
+        }
+        catch (Exception ex)
+        {
+            throw new ArgumentException($"布尔表达式解析失败:{booleanExpression},错误:{ex.Message}", ex);
+        }
+    }
+
+    /// <summary>
+    /// 核心函数处理逻辑(直接写,避免任何匹配误差)
+    /// </summary>
+    private static void OnEvaluateFunction(string funcName, FunctionArgs args)
+    {
+        // 注册 Contains 函数(核心新增)
+        if (funcName == "Contains")
+        {
+            if (args.Parameters.Length != 2)
+            {
+                throw new ArgumentException("Contains 必须传入 2 个参数:字符串、子串");
+            }
+            // 安全获取参数(避免 null/空字符串解析问题)
+            var str = args.Parameters[0].Evaluate()?.ToString() ?? string.Empty;
+            var subStr = args.Parameters[1].Evaluate()?.ToString() ?? string.Empty;
+            args.Result = str.Contains(subStr);
+            return;
+        }
+        
+        // 方案1:精准匹配(表达式写 StartsWith 就匹配 StartsWith)
+        if (funcName == "StartsWith")
+        {
+            // 严格校验参数数量
+            if (args.Parameters.Length != 2)
+            {
+                throw new ArgumentException("StartsWith 必须传入 2 个参数:字符串、前缀");
+            }
+            // 安全获取参数值(避免 null)
+            var str = args.Parameters[0].Evaluate()?.ToString() ?? string.Empty;
+            var prefix = args.Parameters[1].Evaluate()?.ToString() ?? string.Empty;
+            // 执行原生 StartsWith
+            args.Result = str.StartsWith(prefix);
+            return;
+        }
+
+        // 方案1:精准匹配 IsNullOrEmpty
+        if (funcName == "IsNullOrEmpty")
+        {
+            if (args.Parameters.Length != 1)
+            {
+                throw new ArgumentException("IsNullOrEmpty 必须传入 1 个参数:字符串");
+            }
+            var value = args.Parameters[0].Evaluate()?.ToString();
+            args.Result = string.IsNullOrEmpty(value);
+            return;
+        }
+
+        // 未找到函数时明确报错
+        throw new ArgumentException($"未定义函数:{funcName}");
+    }
+
 
 }