Skip to content

Commit 17178ee

Browse files
Florian KroenertFlorian Kroenert
authored andcommitted
Added FormatString function and possibility to define OutputParameters
1 parent 6a94679 commit 17178ee

4 files changed

Lines changed: 63 additions & 11 deletions

File tree

build.fsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ let sha = Git.Information.getCurrentHash()
3535
// version info
3636
let major = "3"
3737
let minor = "9"
38-
let patch = "13"
38+
let patch = "14"
3939

4040
// Follow SemVer scheme: http://semver.org/
4141
let asmVersion = major + "." + minor + "." + patch

src/lib/Xrm.Oss.XTL.Interpreter/FunctionHandlers.cs

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,30 +1039,78 @@ private static T CheckedCast<T>(object input, string errorMessage, bool failOnEr
10391039
return new ValueExpression(date.ToString(CultureInfo.InvariantCulture), date.ToString(CultureInfo.InvariantCulture));
10401040
};
10411041

1042+
/// <summary>
1043+
/// Formats a single value with a format specifier (like .ToString(format))
1044+
/// </summary>
10421045
public static FunctionHandler Format = (primary, service, tracing, interpreterConfig, parameters) =>
10431046
{
10441047
if (parameters.Count < 2)
10451048
{
1046-
throw new InvalidPluginExecutionException("Format needs a value to format and a config for defining further options");
1049+
throw new InvalidPluginExecutionException("Format needs a value and a format string");
10471050
}
10481051

10491052
var value = parameters[0].Value;
1053+
1054+
// Handle special CRM types
1055+
if (value is Money money) value = money.Value;
1056+
if (value is OptionSetValue optionSet) value = optionSet.Value;
1057+
1058+
// Support both styles:
1059+
// Format(value, { format: "C2" })
1060+
// Format(value, { format: "{0:C2}" })
10501061
var config = GetConfig(parameters);
1051-
var format = config.GetValue<string>("format", "format must be a string!");
1062+
var formatString = config.GetValue<string>("format", "format must be a string!");
1063+
1064+
try
1065+
{
1066+
string formatted;
1067+
1068+
// If format contains {0:, use string.Format
1069+
if (formatString.Contains("{0:") || formatString.Contains("{0}"))
1070+
{
1071+
formatted = string.Format(CultureInfo.InvariantCulture, formatString, value);
1072+
}
1073+
// Otherwise, use direct formatting
1074+
else if (value is IFormattable formattable)
1075+
{
1076+
formatted = formattable.ToString(formatString, CultureInfo.InvariantCulture);
1077+
}
1078+
else
1079+
{
1080+
formatted = value?.ToString() ?? string.Empty;
1081+
}
1082+
1083+
return new ValueExpression(formatted, formatted);
1084+
}
1085+
catch (FormatException ex)
1086+
{
1087+
throw new InvalidPluginExecutionException($"Invalid format '{formatString}': {ex.Message}");
1088+
}
1089+
};
10521090

1053-
var knownTypes = new Dictionary<Type, Func<object, ValueExpression>>
1091+
/// <summary>
1092+
/// Composes multiple values into a format string (like string.Format)
1093+
/// </summary>
1094+
public static FunctionHandler FormatString = (primary, service, tracing, interpreterConfig, parameters) =>
1095+
{
1096+
if (parameters.Count < 1)
10541097
{
1055-
{ typeof(Money), (obj) => { var val = obj as Money; var formatted = string.Format(CultureInfo.InvariantCulture, format, val.Value); return new ValueExpression( formatted, formatted ); } }
1056-
};
1098+
throw new InvalidPluginExecutionException("FormatString needs at least a format string");
1099+
}
10571100

1058-
if(knownTypes.ContainsKey(value.GetType()))
1101+
var format = CheckedCast<string>(parameters[0].Value, "First parameter must be a format string");
1102+
1103+
// Positional parameters only - exactly like C# string.Format
1104+
var args = parameters.Skip(1).Select(p => p.Value).ToArray();
1105+
1106+
try
10591107
{
1060-
return knownTypes[value.GetType()](value);
1108+
var result = string.Format(CultureInfo.InvariantCulture, format, args);
1109+
return new ValueExpression(result, result);
10611110
}
1062-
else
1111+
catch (FormatException ex)
10631112
{
1064-
var formatted = string.Format(CultureInfo.InvariantCulture, format, value);
1065-
return new ValueExpression(formatted, formatted);
1113+
throw new InvalidPluginExecutionException($"Invalid format string: {ex.Message}");
10661114
}
10671115
};
10681116

src/lib/Xrm.Oss.XTL.Interpreter/InterpreterConfig.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public class InterpreterConfig : IConfig
4343
[DataMember(Name = "inputParameters")]
4444
public Dictionary<string, object> InputParameters { get; set; } = new Dictionary<string, object>();
4545

46+
[DataMember(Name = "outputParameters")]
47+
public Dictionary<string, object> OutputParameters { get; set; } = new Dictionary<string, object>();
48+
4649
public Dictionary<string, FunctionHandler> CustomHandlers { get; set; } = new Dictionary<string, FunctionHandler>();
4750

4851
public static InterpreterConfig Parse(string json)

src/lib/Xrm.Oss.XTL.Interpreter/XTLInterpreter.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class XTLInterpreter
3636
{ "Filter", FunctionHandlers.Filter },
3737
{ "First", FunctionHandlers.First },
3838
{ "Format", FunctionHandlers.Format },
39+
{ "FormatString", FunctionHandlers.FormatString },
3940
{ "GptPrompt", FunctionHandlers.GptPrompt },
4041
{ "If", FunctionHandlers.If },
4142
{ "IndexOf", FunctionHandlers.IndexOf },

0 commit comments

Comments
 (0)