From 34a875db053c219536b9b2de54f89e67186b842c Mon Sep 17 00:00:00 2001 From: Bensong Liu <bensl@microsoft.com> Date: Tue, 20 Oct 2020 17:37:44 +0800 Subject: [PATCH] allow explicit argument and ignore argument --- activity.hpp | 69 +++++++++++++++++++++++++++++++---------- uuid.hpp => utility.hpp | 12 ++++++- xaml-template.hpp | 21 +++++++++---- xaml.gen.example.cc | 6 +++- 4 files changed, 83 insertions(+), 25 deletions(-) rename uuid.hpp => utility.hpp (70%) diff --git a/activity.hpp b/activity.hpp index db46a1a..2bcfcae 100644 --- a/activity.hpp +++ b/activity.hpp @@ -9,7 +9,7 @@ #include <queue> #include <algorithm> -#include "uuid.hpp" +#include "utility.hpp" #include "xaml-template.hpp" #include <rlib/string.hpp> #include <rlib/require/cxx14> @@ -24,39 +24,74 @@ namespace CIS { class Activity { public: friend Flow; + // All `Name` should not contain QuotationMark(") Activity(string displayName, string className, string entityName = "") - : displayName(displayName), className(className), entityName(entityName), taskId(GenUUID()) {} + : displayName(Utility::HtmlEscapeString(displayName)), className(className), entityName(entityName), taskId(Utility::GenUUID()) {} Flow operator>>(const Flow &seqNext) const; Flow operator|(const Flow &seqNext) const; void addInputSetting(string k, string v) { inputSettings[k] = v; } - void addRawActivityArgument(string xamlTypeString, string csharpValueCode) { - throw std::invalid_argument("Not implemented yet."); + void explicitSetRawArgument(string argTypeInXaml, string argValueInCSharp) { + explicitArgType = argTypeInXaml; + explicitArgValue = argValueInCSharp; } private: string displayName, className, entityName; string taskId; std::unordered_map<string, string> inputSettings; + + string explicitArgType, explicitArgValue; + + auto inputSettingsToCodelines() const { + // Convert InputSettings Dictionary to C# code. + std::list<string> inputSettingStrings; + std::transform(this->inputSettings.begin(), this->inputSettings.end(), std::back_inserter(inputSettingStrings), [](auto &&kv) { + return " {\"{}\", \"{}\"}"_rs.format(kv.first, kv.second); + }); + auto inputSettingsString = ",\n"_rs.join(inputSettingStrings); + return rlib::string(templates::ACTIVITY_DICT_TEMPLATE_UNESCAPED).replace_once("__TEMPLATE_ARG_DictLines", inputSettingsString); + } + auto generateXaml() const { + rlib::string xamlCode = templates::ACTIVITY_XAML_TEMPLATE; + + string argType, argValue; + if(explicitArgType.empty() && explicitArgValue.empty()) { + // no explicit argument specified. + if(inputSettings.empty()) { + // Also no inputSettings. + xamlCode = templates::ACTIVITY_XAML_TEMPLATE_WITHOUT_INPUTSETTINGS; + } + else { + // Generate inputSettings. + argType = templates::ACTIVITY_DICT_TYPENAME; + argValue = inputSettingsToCodelines(); + } + } + else { + // Use explicit argument. + argType = explicitArgType; + argValue = explicitArgValue; + } + + xamlCode.replace("__TEMPLATE_ARG_TypeName", argType); + xamlCode.replace_once("__TEMPLATE_ARG_TypeValue", argValue); + xamlCode.replace_once("__TEMPLATE_ARG_ClassName", this->className); + xamlCode.replace_once("__TEMPLATE_ARG_DisplayName", this->displayName); + xamlCode.replace_once("__TEMPLATE_ARG_TaskId", this->taskId); + + auto entityXaml = this->entityName == "" ? "" : rlib::string(templates::ENTITY_DEF_TEMPLATE).replace("__TEMPLATE_ARG_EntityName", this->entityName); + xamlCode.replace_once("__TEMPLATE_ARG_EntityDefPlaceholder", entityXaml); + + return xamlCode; + } }; class Flow { public: Flow(const Activity &activity) { - xamlCode = templates::ACTIVITY_XAML_TEMPLATE; - xamlCode.replace_once("__TEMPLATE_ARG_ClassName", activity.className); - xamlCode.replace_once("__TEMPLATE_ARG_DisplayName", activity.displayName); - xamlCode.replace_once("__TEMPLATE_ARG_TaskId", activity.taskId); - auto entityXaml = activity.entityName == "" ? "" : rlib::string(templates::ENTITY_DEF_TEMPLATE).replace("__TEMPLATE_ARG_EntityName", activity.entityName); - xamlCode.replace_once("__TEMPLATE_ARG_EntityDefPlaceholder", entityXaml); - - std::list<string> inputSettingStrings; - std::transform(activity.inputSettings.begin(), activity.inputSettings.end(), std::back_inserter(inputSettingStrings), [](auto &&kv) { - return "{\"{}\", \"{}\"}"_rs.format(kv.first, kv.second); - }); - auto inputSettingsString = ",\n "_rs.join(inputSettingStrings); - xamlCode.replace_once("__TEMPLATE_ARG_DictLines", inputSettingsString); + xamlCode = activity.generateXaml(); } Flow(rlib::string xamlCode) : xamlCode(xamlCode) {} Flow(const Flow &another) : queued(another.queued), xamlCode(another.xamlCode), prevOperationIsSequential(another.prevOperationIsSequential) {} diff --git a/uuid.hpp b/utility.hpp similarity index 70% rename from uuid.hpp rename to utility.hpp index 35167b0..da1f935 100644 --- a/uuid.hpp +++ b/utility.hpp @@ -3,8 +3,12 @@ #include <random> #include <string> +#include <rlib/string.hpp> -inline static std::string GenUUID() { +namespace Utility { + + +inline static auto GenUUID() { static std::random_device dev; static std::mt19937 rng(dev()); @@ -22,4 +26,10 @@ inline static std::string GenUUID() { return res; } +inline static auto HtmlEscapeString(rlib::string s) { + return s.replace("&", "&").replace("<", "<").replace(">", ">"); +} + +} + #endif \ No newline at end of file diff --git a/xaml-template.hpp b/xaml-template.hpp index 26215f6..58a26eb 100644 --- a/xaml-template.hpp +++ b/xaml-template.hpp @@ -12,17 +12,26 @@ namespace templates { constexpr auto ACTIVITY_XAML_TEMPLATE = R"XAMLTL( <mwcwa:ControlledActivity ClassName="__TEMPLATE_ARG_ClassName" DisplayName="__TEMPLATE_ARG_DisplayName" TaskId="__TEMPLATE_ARG_TaskId" __TEMPLATE_ARG_EntityDefPlaceholder> <mwcwa:ControlledActivity.InputSettings> - <InArgument x:TypeArguments="scg:Dictionary(x:String, x:String)"> - <mca:CSharpValue x:TypeArguments="scg:Dictionary(x:String, x:String)" xml:space="preserve"> - new Dictionary<string, string>() - { - __TEMPLATE_ARG_DictLines - } + <InArgument x:TypeArguments="__TEMPLATE_ARG_TypeName"> + <mca:CSharpValue x:TypeArguments="__TEMPLATE_ARG_TypeName" xml:space="preserve"> +__TEMPLATE_ARG_TypeValue </mca:CSharpValue> </InArgument> </mwcwa:ControlledActivity.InputSettings> </mwcwa:ControlledActivity> )XAMLTL"; +constexpr auto ACTIVITY_XAML_TEMPLATE_WITHOUT_INPUTSETTINGS = +R"XAMLTL( <mwcwa:ControlledActivity ClassName="__TEMPLATE_ARG_ClassName" DisplayName="__TEMPLATE_ARG_DisplayName" TaskId="__TEMPLATE_ARG_TaskId" InputSettings="{x:Null}" __TEMPLATE_ARG_EntityDefPlaceholder> + </mwcwa:ControlledActivity> +)XAMLTL"; + +constexpr auto ACTIVITY_DICT_TYPENAME = "scg:Dictionary(x:String, x:String)"; +constexpr auto ACTIVITY_DICT_TEMPLATE_UNESCAPED = +R"XAMLTL( new Dictionary<string, string>() + { +__TEMPLATE_ARG_DictLines + } +)XAMLTL"; constexpr auto ENTITY_DEF_TEMPLATE = R"(coordination:DependencyBinder.EntityName="__TEMPLATE_ARG_EntityName")"; diff --git a/xaml.gen.example.cc b/xaml.gen.example.cc index 91a467b..b0f8618 100644 --- a/xaml.gen.example.cc +++ b/xaml.gen.example.cc @@ -31,10 +31,14 @@ auto complexExample() { DEFINE_ACTIVITY(IntegrationTesting, "") DEFINE_ACTIVITY(TSConfigAndInterop, "PreRteg.InitiateBareMetalComplete") + // All Names of activity should not contain quotation mark (") + Activity OneMoreMagicActivity("MyName Contains Symbols: {(<&>)}", "FleetAGC.Workflow.Magic"); + OneMoreMagicActivity.explicitSetRawArgument("x:Boolean", "(0b_1100_1000 | 0b_1000_0001 == 201)"); + auto block1 = SCS >> (SearchAnalytics | (SearchFarms >> (ClassisSearchUX | ModernSearch))); auto block3 = Loki >> Yggdrasil >> OfficeGraph; auto block4 = IC3Tooling >> (MonitoringSetup | (MicroServices >> DevelopmentValidation >> IntegrationTesting)); - auto completeFlow = block1 | TSConfigAndInterop | block3 | block4; + auto completeFlow = (block1 | TSConfigAndInterop | block3 | block4) >> OneMoreMagicActivity; auto myMetadata = Metadata("FleetAGC.Workflows.BuildTeams").setXtraAssemblies({"FleetAGC.Workflows"}); println(to_file("BuildTeams.xaml"), completeFlow.generateXaml(myMetadata)); -- GitLab