From 2c73f35fa17dd788189be0b5d58432e95fce4a73 Mon Sep 17 00:00:00 2001 From: HaseenaSainul Date: Tue, 28 Nov 2023 09:30:57 -0500 Subject: [PATCH] CPPSDK: provider support added --- languages/cpp/language.config.json | 1 + languages/cpp/src/shared/include/types.h | 1 + .../sub-property/property.cpp | 2 +- .../callback-result-instantiation/enum.cpp | 2 +- .../sub-property/array.cpp | 2 +- .../cpp/templates/codeblocks/interface.cpp | 47 +++++++ .../cpp/templates/codeblocks/interface.h | 12 ++ .../codeblocks/provider-subscribe.cpp | 1 + .../cpp/templates/codeblocks/provider.cpp | 1 + languages/cpp/templates/codeblocks/provider.h | 1 + .../cpp/templates/codeblocks/subscribe.cpp | 5 + .../declarations-override/calls-metrics.h | 1 - .../templates/declarations-override/provide.h | 1 + .../templates/declarations/calls-metrics.h | 1 - .../cpp/templates/declarations/provide.h | 1 + .../cpp/templates/interfaces/default.cpp | 17 +++ languages/cpp/templates/interfaces/default.h | 1 + .../cpp/templates/interfaces/focusable.cpp | 44 +++++++ .../cpp/templates/interfaces/focusable.h | 1 + languages/cpp/templates/json-types/integer.h | 2 +- .../cpp/templates/methods/calls-metrics.cpp | 1 - languages/cpp/templates/methods/default.cpp | 3 + .../methods/polymorphic-pull-event.cpp | 3 +- .../templates/methods/polymorphic-pull.cpp | 3 + languages/cpp/templates/methods/provide.cpp | 8 ++ .../cpp/templates/modules/include/module.h | 5 +- .../cpp/templates/modules/src/module_impl.cpp | 3 +- .../additionalProperties.cpp | 7 +- .../parameter-serialization/array.cpp | 10 +- .../parameter-serialization/enum.cpp | 8 +- .../parameter-serialization/generic.cpp | 7 +- .../parameter-serialization/object-array.cpp | 4 +- .../object-empty-property.cpp | 7 +- .../parameter-serialization/object.cpp | 15 ++- .../parameter-serialization/property.cpp | 4 +- .../sub-property/anyOfSchemaShape.cpp | 4 +- .../sub-property/array.cpp | 19 ++- .../sub-property/const.cpp | 4 +- .../sub-property/object-array.cpp | 4 +- .../sub-property/property.cpp | 4 +- .../sections/provider-interfaces.cpp | 1 + .../templates/sections/provider-interfaces.h | 21 ++-- .../templates/sections/provider-subscribe.cpp | 1 + src/macrofier/engine.mjs | 116 ++++++++++++++++-- src/macrofier/index.mjs | 2 + src/macrofier/types.mjs | 32 +++-- src/sdk/index.mjs | 1 + src/shared/modules.mjs | 91 +++++++------- 48 files changed, 418 insertions(+), 114 deletions(-) create mode 100644 languages/cpp/templates/codeblocks/interface.cpp create mode 100644 languages/cpp/templates/codeblocks/interface.h create mode 100644 languages/cpp/templates/codeblocks/provider-subscribe.cpp create mode 100644 languages/cpp/templates/codeblocks/provider.cpp create mode 100644 languages/cpp/templates/codeblocks/provider.h create mode 100644 languages/cpp/templates/codeblocks/subscribe.cpp create mode 100644 languages/cpp/templates/interfaces/default.cpp create mode 100644 languages/cpp/templates/interfaces/default.h create mode 100644 languages/cpp/templates/interfaces/focusable.cpp create mode 100644 languages/cpp/templates/interfaces/focusable.h create mode 100644 languages/cpp/templates/sections/provider-interfaces.cpp create mode 100644 languages/cpp/templates/sections/provider-subscribe.cpp diff --git a/languages/cpp/language.config.json b/languages/cpp/language.config.json index db9b7ddc..8c5f533e 100644 --- a/languages/cpp/language.config.json +++ b/languages/cpp/language.config.json @@ -6,6 +6,7 @@ "unwrapResultObjects": false, "createPolymorphicMethods": true, "excludeDeclarations": true, + "extractProviderSchema": true, "aggregateFiles": [ "/include/firebolt.h", "/src/firebolt.cpp" diff --git a/languages/cpp/src/shared/include/types.h b/languages/cpp/src/shared/include/types.h index 841bda7a..7546ca2f 100644 --- a/languages/cpp/src/shared/include/types.h +++ b/languages/cpp/src/shared/include/types.h @@ -24,4 +24,5 @@ #include #include #include +#include diff --git a/languages/cpp/templates/callback-context-instantiation/sub-property/property.cpp b/languages/cpp/templates/callback-context-instantiation/sub-property/property.cpp index 0d95dcab..4276ebc4 100644 --- a/languages/cpp/templates/callback-context-instantiation/sub-property/property.cpp +++ b/languages/cpp/templates/callback-context-instantiation/sub-property/property.cpp @@ -1 +1 @@ -${shape} ${if.non.const}${if.non.anyOf}${if.non.array}${if.non.object}${base.title}${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property} = response.${Property.dependency}${Property};${end.if.non.object}${end.if.non.array}${end.if.non.anyOf}${end.if.non.const} +${shape} ${if.non.const}${if.non.anyOf}${if.non.array}${if.non.object}${base.title}${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property} = response.${Property.dependency}${Property};${end.if.non.object}${end.if.non.array}${end.if.non.anyOf}${end.if.non.const} \ No newline at end of file diff --git a/languages/cpp/templates/callback-result-instantiation/enum.cpp b/languages/cpp/templates/callback-result-instantiation/enum.cpp index d5bc4150..6d8fa873 100644 --- a/languages/cpp/templates/callback-result-instantiation/enum.cpp +++ b/languages/cpp/templates/callback-result-instantiation/enum.cpp @@ -1 +1 @@ - ${if.namespace.notsame}${info.Title}::${end.if.namespace.notsame}${title} response = proxyResponse->Value(); \ No newline at end of file + ${property} = proxyResponse->Value(); \ No newline at end of file diff --git a/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp b/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp index 03910b83..8bf38da1 100644 --- a/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp +++ b/languages/cpp/templates/callback-result-instantiation/sub-property/array.cpp @@ -1,4 +1,4 @@ - ${if.impl.array.optional}${base.title}.${property} = std::make_optional<${type}>();${end.if.impl.array.optional} + ${if.impl.array.optional}${base.title}.${property} = std::make_optional<${type}>();${end.if.impl.array.optional} auto index(proxyResponse->${Property}.Elements()); while (index.Next() == true) { ${if.object}${items.with.indent}${end.if.object}${if.non.object} ${base.title}.${property}${if.impl.array.optional}.value()${end.if.impl.array.optional}.push_back(index.Current().Value());${end.if.non.object} diff --git a/languages/cpp/templates/codeblocks/interface.cpp b/languages/cpp/templates/codeblocks/interface.cpp new file mode 100644 index 00000000..dff9252d --- /dev/null +++ b/languages/cpp/templates/codeblocks/interface.cpp @@ -0,0 +1,47 @@ + static void ProviderInvokeSession(std::string& methodName, JsonObject& jsonParameters, Firebolt::Error *err = nullptr) + { + Firebolt::Error status = Firebolt::Error::NotConnected; + FireboltSDK::Transport* transport = FireboltSDK::Accessor::Instance().GetTransport(); + if (transport != nullptr) { + + JsonObject jsonResult; + status = transport->Invoke(methodName, jsonParameters, jsonResult); + if (status == Firebolt::Error::None) { + FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "%s is successfully invoked", methodName.c_str()); + } + + } else { + FIREBOLT_LOG_ERROR(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "Error in getting Transport err = %d", status); + } + if (err != nullptr) { + *err = status; + } + } + static void ProviderFocusSession(std::string methodName, std::string& correlationId, Firebolt::Error *err = nullptr) + { + JsonObject jsonParameters; + WPEFramework::Core::JSON::Variant CorrelationId(correlationId); + jsonParameters.Set(_T("correlationId"), CorrelationId); + + ProviderInvokeSession(methodName, jsonParameters, err); + } + static void ProviderResultSession(std::string methodName, std::string& correlationId, ${provider.xresponse.name} result, Firebolt::Error *err = nullptr) + { + JsonObject jsonParameters; + WPEFramework::Core::JSON::Variant CorrelationId(correlationId); + jsonParameters.Set(_T("correlationId"), CorrelationId); + +${provider.xresponse.serialization} + ProviderInvokeSession(methodName, jsonParameters, err); + } + static void ProviderErrorSession(std::string methodName, std::string& correlationId, ${provider.xerror.name} result, Firebolt::Error *err = nullptr) + { + JsonObject jsonParameters; + WPEFramework::Core::JSON::Variant CorrelationId(correlationId); + jsonParameters.Set(_T("correlationId"), CorrelationId); + +${provider.xerror.serialization} + ProviderInvokeSession(methodName, jsonParameters, err); + } + +${methods} diff --git a/languages/cpp/templates/codeblocks/interface.h b/languages/cpp/templates/codeblocks/interface.h new file mode 100644 index 00000000..376426ee --- /dev/null +++ b/languages/cpp/templates/codeblocks/interface.h @@ -0,0 +1,12 @@ +struct I${info.Title}Session : virtual public IFocussableProviderSession { + virtual ~I${info.Title}Session() override = default; + + virtual void error( ${provider.xerror.name} error, Firebolt::Error *err = nullptr ) = 0; + virtual void result( ${provider.xresponse.name} result, Firebolt::Error *err = nullptr ) = 0; +}; + +struct I${info.Title}Provider { + virtual ~I${info.Title}Provider() = default; + +${methods} +}; \ No newline at end of file diff --git a/languages/cpp/templates/codeblocks/provider-subscribe.cpp b/languages/cpp/templates/codeblocks/provider-subscribe.cpp new file mode 100644 index 00000000..88c3dffe --- /dev/null +++ b/languages/cpp/templates/codeblocks/provider-subscribe.cpp @@ -0,0 +1 @@ +${subscribe} \ No newline at end of file diff --git a/languages/cpp/templates/codeblocks/provider.cpp b/languages/cpp/templates/codeblocks/provider.cpp new file mode 100644 index 00000000..5b4cf7b8 --- /dev/null +++ b/languages/cpp/templates/codeblocks/provider.cpp @@ -0,0 +1 @@ +${interface} \ No newline at end of file diff --git a/languages/cpp/templates/codeblocks/provider.h b/languages/cpp/templates/codeblocks/provider.h new file mode 100644 index 00000000..b2895fe0 --- /dev/null +++ b/languages/cpp/templates/codeblocks/provider.h @@ -0,0 +1 @@ +${interface} diff --git a/languages/cpp/templates/codeblocks/subscribe.cpp b/languages/cpp/templates/codeblocks/subscribe.cpp new file mode 100644 index 00000000..4039ca95 --- /dev/null +++ b/languages/cpp/templates/codeblocks/subscribe.cpp @@ -0,0 +1,5 @@ + eventName = _T("${info.title.lowercase}.onRequest${method.Name}"); + status = FireboltSDK::Event::Instance().Subscribe<${event.result.json.type}>(eventName, jsonParameters, ${info.Title}${method.Name}SessionInnerCallback, reinterpret_cast(&provider), nullptr); + if (status != Firebolt::Error::None) { + FIREBOLT_LOG_ERROR(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "Error in %s subscribe = %d", eventName.c_str(), status); + } diff --git a/languages/cpp/templates/declarations-override/calls-metrics.h b/languages/cpp/templates/declarations-override/calls-metrics.h index 8b137891..e69de29b 100644 --- a/languages/cpp/templates/declarations-override/calls-metrics.h +++ b/languages/cpp/templates/declarations-override/calls-metrics.h @@ -1 +0,0 @@ - diff --git a/languages/cpp/templates/declarations-override/provide.h b/languages/cpp/templates/declarations-override/provide.h index e69de29b..5fca741f 100644 --- a/languages/cpp/templates/declarations-override/provide.h +++ b/languages/cpp/templates/declarations-override/provide.h @@ -0,0 +1 @@ + void provide( I${info.Title}Provider& provider ) override; diff --git a/languages/cpp/templates/declarations/calls-metrics.h b/languages/cpp/templates/declarations/calls-metrics.h index 8b137891..e69de29b 100644 --- a/languages/cpp/templates/declarations/calls-metrics.h +++ b/languages/cpp/templates/declarations/calls-metrics.h @@ -1 +0,0 @@ - diff --git a/languages/cpp/templates/declarations/provide.h b/languages/cpp/templates/declarations/provide.h index e69de29b..0cd03159 100644 --- a/languages/cpp/templates/declarations/provide.h +++ b/languages/cpp/templates/declarations/provide.h @@ -0,0 +1 @@ + virtual void provide( I${info.Title}Provider& provider ) = 0; diff --git a/languages/cpp/templates/interfaces/default.cpp b/languages/cpp/templates/interfaces/default.cpp new file mode 100644 index 00000000..4cba2764 --- /dev/null +++ b/languages/cpp/templates/interfaces/default.cpp @@ -0,0 +1,17 @@ + class ${info.Title}${method.Name}Session : virtual public IProviderSession { + public: + std::string correlationId () const override + { + return _correlationId; + } + + public: + std::string _correlationId; + }; + static void ${info.Title}${method.Name}SessionInnerCallback( void* provider, const void* userData, void* jsonResponse ) + { + //TODO: code to convert jsonResponse to ${method.name} session + I${info.Title}Provider& ${info.title.lowercase}Provider = *(reinterpret_cast(provider)); + ${info.title.lowercase}Provider.${method.name}( parameters, session ); + } + diff --git a/languages/cpp/templates/interfaces/default.h b/languages/cpp/templates/interfaces/default.h new file mode 100644 index 00000000..05ebc463 --- /dev/null +++ b/languages/cpp/templates/interfaces/default.h @@ -0,0 +1 @@ + virtual void ${method.name}( ${method.signature.params}, IProviderSession& session ) = 0; \ No newline at end of file diff --git a/languages/cpp/templates/interfaces/focusable.cpp b/languages/cpp/templates/interfaces/focusable.cpp new file mode 100644 index 00000000..9a8d859d --- /dev/null +++ b/languages/cpp/templates/interfaces/focusable.cpp @@ -0,0 +1,44 @@ + class ${info.Title}${method.Name}Session : virtual public I${info.Title}Session { + public: + ${info.Title}${method.Name}Session( const std::string& correlationId ) + : _correlationId(correlationId) + { + } + + std::string correlationId() const override + { + return _correlationId; + } + void focus( Firebolt::Error *err = nullptr ) override + { + ProviderFocusSession("${info.title.lowercase}.${method.name}Focus", _correlationId, err); + } + void result( ${provider.xresponse.name} response, Firebolt::Error *err = nullptr ) override + { + ProviderResultSession("${info.title.lowercase}.${method.name}Response", _correlationId, response, err); + } + void error( ${provider.xerror.name} error, Firebolt::Error *err = nullptr ) override + { + ProviderErrorSession("${info.title.lowercase}.${method.name}Error", _correlationId, error, err); + } + + public: + std::string _correlationId; + }; + static void ${info.Title}${method.Name}SessionInnerCallback( void* provider, const void* userData, void* jsonResponse ) + { +${event.callback.serialization} + ASSERT(proxyResponse.IsValid() == true); + + if (proxyResponse.IsValid() == true) { +${event.callback.initialization} + +${event.callback.instantiation} + proxyResponse.Release(); + + std::unique_ptr ${info.title.lowercase}${method.Name}Session = std::make_unique<${info.Title}${method.Name}Session>(${method.result.name}.correlationId); + I${info.Title}Provider& ${info.title.lowercase}Provider = *(reinterpret_cast(provider)); + ${info.title.lowercase}Provider.${method.name}(${method.result.name}.parameters, std::move(${info.title.lowercase}${method.Name}Session)); + } + } + diff --git a/languages/cpp/templates/interfaces/focusable.h b/languages/cpp/templates/interfaces/focusable.h new file mode 100644 index 00000000..a967e096 --- /dev/null +++ b/languages/cpp/templates/interfaces/focusable.h @@ -0,0 +1 @@ + virtual void ${method.name}( ${method.signature.params}, std::unique_ptr session ) = 0; diff --git a/languages/cpp/templates/json-types/integer.h b/languages/cpp/templates/json-types/integer.h index 4bf0dddb..b57fe26e 100644 --- a/languages/cpp/templates/json-types/integer.h +++ b/languages/cpp/templates/json-types/integer.h @@ -1 +1 @@ -WPEFramework::Core::JSON::DecSInt32 +WPEFramework::Core::JSON::DecSInt32 \ No newline at end of file diff --git a/languages/cpp/templates/methods/calls-metrics.cpp b/languages/cpp/templates/methods/calls-metrics.cpp index 8b137891..e69de29b 100644 --- a/languages/cpp/templates/methods/calls-metrics.cpp +++ b/languages/cpp/templates/methods/calls-metrics.cpp @@ -1 +0,0 @@ - diff --git a/languages/cpp/templates/methods/default.cpp b/languages/cpp/templates/methods/default.cpp index fbeaf160..f1fb6e71 100644 --- a/languages/cpp/templates/methods/default.cpp +++ b/languages/cpp/templates/methods/default.cpp @@ -18,6 +18,9 @@ } else { FIREBOLT_LOG_ERROR(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "Error in getting Transport err = %d", status); } + if (err != nullptr) { + *err = status; + } return${if.result.nonvoid} ${method.result.name}${end.if.result.nonvoid}; } diff --git a/languages/cpp/templates/methods/polymorphic-pull-event.cpp b/languages/cpp/templates/methods/polymorphic-pull-event.cpp index 2bcf6c5f..ef7a837b 100644 --- a/languages/cpp/templates/methods/polymorphic-pull-event.cpp +++ b/languages/cpp/templates/methods/polymorphic-pull-event.cpp @@ -18,8 +18,9 @@ WPEFramework::Core::JSON::Variant CorrelationId = proxyResponse->CorrelationId.Value(); jsonParameters.Set(_T("correlationId"), CorrelationId); ${method.pulls.json.type} ${method.pulls.result.title}Container; - + { ${method.pulls.result.serialization.with.indent} + } string resultStr; ${method.pulls.result.title}Container.ToString(resultStr); WPEFramework::Core::JSON::VariantContainer resultContainer(resultStr); diff --git a/languages/cpp/templates/methods/polymorphic-pull.cpp b/languages/cpp/templates/methods/polymorphic-pull.cpp index d919d349..7f8368d2 100644 --- a/languages/cpp/templates/methods/polymorphic-pull.cpp +++ b/languages/cpp/templates/methods/polymorphic-pull.cpp @@ -18,6 +18,9 @@ } else { FIREBOLT_LOG_ERROR(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module(), "Error in getting Transport err = %d", status); } + if (err != nullptr) { + *err = status; + } return${if.result.nonvoid} ${method.result.name}${end.if.result.nonvoid}; } diff --git a/languages/cpp/templates/methods/provide.cpp b/languages/cpp/templates/methods/provide.cpp index e69de29b..85492d38 100644 --- a/languages/cpp/templates/methods/provide.cpp +++ b/languages/cpp/templates/methods/provide.cpp @@ -0,0 +1,8 @@ + void ${info.Title}Impl::provide( I${info.Title}Provider& provider ) + { + string eventName; + Firebolt::Error status = Firebolt::Error::None; + JsonObject jsonParameters; + + /* ${PROVIDERS_SUBSCRIBE} */ + } diff --git a/languages/cpp/templates/modules/include/module.h b/languages/cpp/templates/modules/include/module.h index de58e77a..04d52aef 100644 --- a/languages/cpp/templates/modules/include/module.h +++ b/languages/cpp/templates/modules/include/module.h @@ -29,15 +29,14 @@ namespace ${info.Title} { /* ${ENUMS} */${end.if.enums} ${if.types} // Types -/* ${TYPES} */ -${end.if.types} +/* ${TYPES} */${end.if.types} +${if.providers}/* ${PROVIDERS} */${end.if.providers} ${if.methods}struct I${info.Title} { virtual ~I${info.Title}() = default; // Methods & Events /* ${METHODS:declarations} */ - };${end.if.methods} } //namespace ${info.Title} diff --git a/languages/cpp/templates/modules/src/module_impl.cpp b/languages/cpp/templates/modules/src/module_impl.cpp index 072cd1fc..36c9b123 100644 --- a/languages/cpp/templates/modules/src/module_impl.cpp +++ b/languages/cpp/templates/modules/src/module_impl.cpp @@ -21,7 +21,8 @@ ${if.implementations} namespace Firebolt { namespace ${info.Title} { - +${if.providers} +/* ${PROVIDERS} */${end.if.providers} // Methods /* ${METHODS} */ diff --git a/languages/cpp/templates/parameter-serialization/additionalProperties.cpp b/languages/cpp/templates/parameter-serialization/additionalProperties.cpp index caa132d9..88c832d0 100644 --- a/languages/cpp/templates/parameter-serialization/additionalProperties.cpp +++ b/languages/cpp/templates/parameter-serialization/additionalProperties.cpp @@ -1,4 +1,7 @@ - ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}${title} map = ${property}${if.impl.optional}.value()${end.if.impl.optional}; + ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}${title} map; + ${if.impl.optional}if (${property}.has_value()) { + map = ${property}.value(); + }${end.if.impl.optional}${if.impl.non.optional}map = ${property};${end.if.impl.non.optional} WPEFramework::Core::JSON::Variant ${property}Variant; for (auto element: map) { WPEFramework::Core::JSON::Variant jsonElement = element.second; @@ -6,4 +9,4 @@ jsonContainer.Set(element.first.c_str(), jsonElement); ${property}Variant = jsonContainer; } - jsonParameters.Set(_T("${property}"), ${property}Variant); + jsonParameters.Set(_T("${property}"), ${property}Variant); \ No newline at end of file diff --git a/languages/cpp/templates/parameter-serialization/array.cpp b/languages/cpp/templates/parameter-serialization/array.cpp index e6559cfb..f623711b 100644 --- a/languages/cpp/templates/parameter-serialization/array.cpp +++ b/languages/cpp/templates/parameter-serialization/array.cpp @@ -1,7 +1,11 @@ WPEFramework::Core::JSON::ArrayType ${property}Array; - for (auto& element : ${property}) { -${if.object}${items.with.indent}${end.if.object}${if.non.object} ${property}Array.Add() = element;${end.if.non.object} - } + ${if.impl.array.optional}if (${property}.has_value()) { + for (auto& element : ${property}.value()) { + ${if.object}${items.with.indent}${end.if.object}${if.non.object} ${property}Array.Add() = element;${end.if.non.object} + } + }${end.if.impl.array.optional}${if.impl.array.non.optional}for (auto& element : ${property}) { +${if.object}${items.with.indent}${end.if.object}${if.non.object} ${property}Array.Add() = element;${end.if.non.object} + }${end.if.impl.array.non.optional} WPEFramework::Core::JSON::Variant ${property}Variant; ${property}Variant.Array(${property}Array); jsonParameters.Set(_T("${property}"), ${property}Variant); \ No newline at end of file diff --git a/languages/cpp/templates/parameter-serialization/enum.cpp b/languages/cpp/templates/parameter-serialization/enum.cpp index 015c6bc6..167761a0 100644 --- a/languages/cpp/templates/parameter-serialization/enum.cpp +++ b/languages/cpp/templates/parameter-serialization/enum.cpp @@ -1,3 +1,7 @@ - ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} jsonValue = ${property}${if.optional}.value()${end.if.optional}; + ${if.optional}if (${property}.has_value()) { + ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} jsonValue = ${property}.value(); + WPEFramework::Core::JSON::Variant ${property}Variant(jsonValue.Data()); + jsonParameters.Set(_T("${property}"), ${property}Variant); + }${end.if.optional}${if.non.optional}${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} jsonValue = ${property}; WPEFramework::Core::JSON::Variant ${property}Variant(jsonValue.Data()); - jsonParameters.Set(_T("${property}"), ${property}Variant); + jsonParameters.Set(_T("${property}"), ${property}Variant);${end.if.non.optional} diff --git a/languages/cpp/templates/parameter-serialization/generic.cpp b/languages/cpp/templates/parameter-serialization/generic.cpp index a2e1525b..5ab016c3 100644 --- a/languages/cpp/templates/parameter-serialization/generic.cpp +++ b/languages/cpp/templates/parameter-serialization/generic.cpp @@ -1,2 +1,5 @@ - WPEFramework::Core::JSON::Variant ${property}Variant(${property}${if.optional}.value()${end.if.optional}); - jsonParameters.Set(_T("${property}"), ${property}Variant); + ${if.optional}if (${property}.has_value()) { + WPEFramework::Core::JSON::Variant ${property}Variant(${property}.value()); + jsonParameters.Set(_T("${property}"), ${property}Variant); + }${end.if.optional}${if.non.optional}WPEFramework::Core::JSON::Variant ${property}Variant(${property}); + jsonParameters.Set(_T("${property}"), ${property}Variant);${end.if.non.optional} diff --git a/languages/cpp/templates/parameter-serialization/object-array.cpp b/languages/cpp/templates/parameter-serialization/object-array.cpp index e8d18cd4..baedcd30 100644 --- a/languages/cpp/templates/parameter-serialization/object-array.cpp +++ b/languages/cpp/templates/parameter-serialization/object-array.cpp @@ -1,7 +1,9 @@ ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} ${property}Container; + { ${properties} + } string ${property}Str; ${property}Container.ToString(${property}Str); WPEFramework::Core::JSON::VariantContainer ${property}VariantContainer(${property}Str); WPEFramework::Core::JSON::Variant ${property}Variant = ${property}VariantContainer; - ${property}Array.Add() = ${property}Variant; \ No newline at end of file + ${property}Array.Add() = ${property}Variant; diff --git a/languages/cpp/templates/parameter-serialization/object-empty-property.cpp b/languages/cpp/templates/parameter-serialization/object-empty-property.cpp index a2e1525b..69893434 100644 --- a/languages/cpp/templates/parameter-serialization/object-empty-property.cpp +++ b/languages/cpp/templates/parameter-serialization/object-empty-property.cpp @@ -1,2 +1,5 @@ - WPEFramework::Core::JSON::Variant ${property}Variant(${property}${if.optional}.value()${end.if.optional}); - jsonParameters.Set(_T("${property}"), ${property}Variant); + ${if.optional}if (${property}.has_value()) { + WPEFramework::Core::JSON::Variant ${property}Variant(${property}.value()); + jsonParameters.Set(_T("${property}"), ${property}Variant); + }${end.if.optional}${if.non.optional}WPEFramework::Core::JSON::Variant ${property}Variant(${property}); + jsonParameters.Set(_T("${property}"), ${property}Variant);${end.if.non.optional} \ No newline at end of file diff --git a/languages/cpp/templates/parameter-serialization/object.cpp b/languages/cpp/templates/parameter-serialization/object.cpp index bd627da6..4d0cbc08 100644 --- a/languages/cpp/templates/parameter-serialization/object.cpp +++ b/languages/cpp/templates/parameter-serialization/object.cpp @@ -1,8 +1,19 @@ - auto element = ${property}${if.impl.optional}.value()${end.if.impl.optional}; + ${if.impl.optional}if (${property}.has_value()) { + auto element = ${property}.value(); + ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} ${property}Container; +${properties} + string ${property}Str; + ${property}Container.ToString(${property}Str); + WPEFramework::Core::JSON::VariantContainer ${property}VariantContainer(${property}Str); + WPEFramework::Core::JSON::Variant ${property}Variant = ${property}VariantContainer; + jsonParameters.Set(_T("${property}"), ${property}Variant); + }${end.if.impl.optional}${if.impl.non.optional}auto element = ${property}; ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} ${property}Container; + { ${properties} + } string ${property}Str; ${property}Container.ToString(${property}Str); WPEFramework::Core::JSON::VariantContainer ${property}VariantContainer(${property}Str); WPEFramework::Core::JSON::Variant ${property}Variant = ${property}VariantContainer; - jsonParameters.Set(_T("${property}"), ${property}Variant); + jsonParameters.Set(_T("${property}"), ${property}Variant);${end.if.impl.non.optional} diff --git a/languages/cpp/templates/parameter-serialization/property.cpp b/languages/cpp/templates/parameter-serialization/property.cpp index e21d52c3..d6bddfdb 100644 --- a/languages/cpp/templates/parameter-serialization/property.cpp +++ b/languages/cpp/templates/parameter-serialization/property.cpp @@ -1 +1,3 @@ -${shape} ${if.non.const}${if.non.anyOf}${if.non.array}${if.non.object}${base.title}Container.${Property} = element.${property}${if.optional}.value()${end.if.optional};${end.if.non.object}${end.if.non.array}${end.if.non.anyOf}${end.if.non.const} \ No newline at end of file +${shape} ${if.non.const}${if.non.anyOf}${if.non.array}${if.non.object}${if.optional}if (element.${property}.has_value()) { + ${base.title}Container.${Property} = element.${property}.value(); + }${end.if.optional}${if.non.optional}${base.title}Container.${Property} = element.${property};${end.if.non.optional}${end.if.non.object}${end.if.non.array}${end.if.non.anyOf}${end.if.non.const} \ No newline at end of file diff --git a/languages/cpp/templates/parameter-serialization/sub-property/anyOfSchemaShape.cpp b/languages/cpp/templates/parameter-serialization/sub-property/anyOfSchemaShape.cpp index a2c3cdd1..7ac47b35 100644 --- a/languages/cpp/templates/parameter-serialization/sub-property/anyOfSchemaShape.cpp +++ b/languages/cpp/templates/parameter-serialization/sub-property/anyOfSchemaShape.cpp @@ -1 +1,3 @@ - ${base.title}Container.${Property.dependency}${Property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}${if.optional}.value()${end.if.optional}; + ${if.optional}if (element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.has_value()) { + ${base.title}Container.${Property.dependency}${Property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.value(); + }${end.if.optional}${if.non.optional}${base.title}Container.${Property.dependency}${Property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property};${end.if.non.optional} \ No newline at end of file diff --git a/languages/cpp/templates/parameter-serialization/sub-property/array.cpp b/languages/cpp/templates/parameter-serialization/sub-property/array.cpp index d71654b0..d04f5448 100644 --- a/languages/cpp/templates/parameter-serialization/sub-property/array.cpp +++ b/languages/cpp/templates/parameter-serialization/sub-property/array.cpp @@ -1,6 +1,13 @@ - WPEFramework::Core::JSON::ArrayType<${json.type}> ${property}Array; - ${type} ${property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}${if.impl.array.optional}.value()${end.if.impl.array.optional}; - for (auto& element : ${property}) { -${if.object}${items.with.indent}${end.if.object}${if.non.object} ${property}Array.Add() = element;${end.if.non.object} - } - ${base.title}Container.${Property.dependency}Add(_T("${property}"), &${property}Array); \ No newline at end of file + ${if.impl.array.optional}if (element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.has_value()) { + WPEFramework::Core::JSON::ArrayType<${json.type}> ${property}Array; + ${type} ${property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.value(); + for (auto& element : ${property}) { + ${if.object}${items.with.indent}${end.if.object}${if.non.object} ${property}Array.Add() = element;${end.if.non.object} + } + ${base.title}Container.${Property.dependency}Add(_T("${property}"), &${property}Array); + }${end.if.impl.array.optional}${if.impl.array.non.optional}WPEFramework::Core::JSON::ArrayType<${json.type}> ${property}Array; + ${type} ${property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}; + for (auto& element : ${property}) { +${if.object}${items.with.indent}${end.if.object}${if.non.object} ${property}Array.Add() = element;${end.if.non.object} + } + ${base.title}Container.${Property.dependency}Add(_T("${property}"), &${property}Array);${end.if.impl.array.non.optional} \ No newline at end of file diff --git a/languages/cpp/templates/parameter-serialization/sub-property/const.cpp b/languages/cpp/templates/parameter-serialization/sub-property/const.cpp index 0b8a51ed..8d41229f 100644 --- a/languages/cpp/templates/parameter-serialization/sub-property/const.cpp +++ b/languages/cpp/templates/parameter-serialization/sub-property/const.cpp @@ -1 +1,3 @@ - ${base.title}Container.${Property.dependency}${Property} = element${property.dependency}.${property}${if.optional}.value()${end.if.optional}; + ${if.optional}if (element${property.dependency}.${property}.has_value()) { + ${base.title}Container.${Property.dependency}${Property} = element${property.dependency}.${property}.value(); + }${end.if.optional}${if.non.optional}${base.title}Container.${Property.dependency}${Property} = element${property.dependency}.${property};${end.if.non.optional} diff --git a/languages/cpp/templates/parameter-serialization/sub-property/object-array.cpp b/languages/cpp/templates/parameter-serialization/sub-property/object-array.cpp index bbb6fabb..a8bca812 100644 --- a/languages/cpp/templates/parameter-serialization/sub-property/object-array.cpp +++ b/languages/cpp/templates/parameter-serialization/sub-property/object-array.cpp @@ -1,3 +1,3 @@ - ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} ${property}Container; + ${if.namespace.notsame}Firebolt::${info.Title}::${end.if.namespace.notsame}JsonData_${title} ${property}Container; ${properties} - ${property}Array.Add() = ${property}Container; \ No newline at end of file + ${property}Array.Add() = ${property}Container; \ No newline at end of file diff --git a/languages/cpp/templates/parameter-serialization/sub-property/property.cpp b/languages/cpp/templates/parameter-serialization/sub-property/property.cpp index 81373225..b7341e97 100644 --- a/languages/cpp/templates/parameter-serialization/sub-property/property.cpp +++ b/languages/cpp/templates/parameter-serialization/sub-property/property.cpp @@ -1 +1,3 @@ -${shape} ${if.non.const}${if.non.anyOf}${if.non.array}${if.non.object}${base.title}Container.${Property.dependency}${Property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}${if.optional}.value()${end.if.optional};${end.if.non.object}${end.if.non.array}${end.if.non.anyOf}${end.if.non.const} +${shape} ${if.non.const}${if.non.anyOf}${if.non.array}${if.non.object}${if.optional}if (element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.has_value()) { + ${base.title}Container.${Property.dependency}${Property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property}.value(); + }${end.if.optional}${if.non.optional}${base.title}Container.${Property.dependency}${Property} = element${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}.${property};${end.if.non.optional}${end.if.non.object}${end.if.non.array}${end.if.non.anyOf}${end.if.non.const} \ No newline at end of file diff --git a/languages/cpp/templates/sections/provider-interfaces.cpp b/languages/cpp/templates/sections/provider-interfaces.cpp new file mode 100644 index 00000000..0198e308 --- /dev/null +++ b/languages/cpp/templates/sections/provider-interfaces.cpp @@ -0,0 +1 @@ +${providers.list} \ No newline at end of file diff --git a/languages/cpp/templates/sections/provider-interfaces.h b/languages/cpp/templates/sections/provider-interfaces.h index 418d7abf..88134258 100644 --- a/languages/cpp/templates/sections/provider-interfaces.h +++ b/languages/cpp/templates/sections/provider-interfaces.h @@ -1,11 +1,14 @@ - // Provider Interfaces +// Provider Interfaces +struct IProviderSession { + virtual ~IProviderSession() = default; - interface ProviderSession { - correlationId(): string // Returns the correlation id of the current provider session - } - - interface FocusableProviderSession extends ProviderSession { - focus(): Promise // Requests that the provider app be moved into focus to prevent a user experience - } + virtual std::string correlationId() const = 0; +}; + +struct IFocussableProviderSession : virtual public IProviderSession { + virtual ~IFocussableProviderSession() override = default; + + virtual void focus( Firebolt::Error *err = nullptr ) = 0; +}; - ${providers.list} \ No newline at end of file +${providers.list} diff --git a/languages/cpp/templates/sections/provider-subscribe.cpp b/languages/cpp/templates/sections/provider-subscribe.cpp new file mode 100644 index 00000000..0198e308 --- /dev/null +++ b/languages/cpp/templates/sections/provider-subscribe.cpp @@ -0,0 +1 @@ +${providers.list} \ No newline at end of file diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index bb9399f2..4d438695 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -56,7 +56,8 @@ let config = { copySchemasIntoModules: false, extractSubSchemas: false, unwrapResultObjects: false, - excludeDeclarations: false + excludeDeclarations: false, + extractProviderSchema: false, } const state = { @@ -397,6 +398,17 @@ const promoteAndNameSubSchemas = (obj) => { // TODO: the `1` below is brittle... should find the index of the non-ListenResponse schema promoteSchema(method.result.schema.anyOf, 1, getPromotionNameFromContentDescriptor(method.result, ''), obj, '#/components/schemas') } + if (method.tags.find(t => t['x-error'])) { + method.tags.forEach(tag => { + if (tag['x-error']) { + const descriptor = { + name: obj.info.title + 'Error', + schema: tag['x-error'] + } + addContentDescriptorSubSchema(descriptor, '', obj) + } + }) + } }) // find non-primitive sub-schemas of components.schemas and name/promote them @@ -551,6 +563,7 @@ const generateMacros = (obj, templates, languages, options = {}) => { } }) + const providerSubscribe = generateProviderSubscribe(obj, templates) const providerInterfaces = generateProviderInterfaces(obj, templates) const defaults = generateDefaults(obj, templates) @@ -567,6 +580,7 @@ const generateMacros = (obj, templates, languages, options = {}) => { defaults, examples, providerInterfaces, + providerSubscribe, version: getSemanticVersion(obj), title: obj.info.title, description: obj.info.description, @@ -612,6 +626,7 @@ const insertMacros = (fContents = '', macros = {}) => { fContents = fContents.replace(/\$\{if\.declarations\}(.*?)\$\{end\.if\.declarations\}/gms, (macros.methods.declarations && macros.methods.declarations.trim() || macros.enums.types.trim()) || macros.types.types.trim()? '$1' : '') fContents = fContents.replace(/\$\{if\.methods\}(.*?)\$\{end\.if\.methods\}/gms, macros.methods.methods.trim() || macros.events.methods.trim() ? '$1' : '') + fContents = fContents.replace(/\$\{if\.providers\}(.*?)\$\{end\.if\.providers\}/gms, macros.providerInterfaces.trim() ? '$1' : '') fContents = fContents.replace(/\$\{if\.implementations\}(.*?)\$\{end\.if\.implementations\}/gms, (macros.methods.methods.trim() || macros.events.methods.trim() || macros.schemas.types.trim()) ? '$1' : '') fContents = fContents.replace(/\$\{module\.list\}/g, macros.module) @@ -650,6 +665,7 @@ const insertMacros = (fContents = '', macros = {}) => { }) fContents = fContents.replace(/[ \t]*\/\* \$\{PROVIDERS\} \*\/[ \t]*\n/, macros.providerInterfaces) + fContents = fContents.replace(/[ \t]*\/\* \$\{PROVIDERS_SUBSCRIBE\} \*\/[ \t]*\n/, macros.providerSubscribe) fContents = fContents.replace(/[ \t]*\/\* \$\{IMPORTS\} \*\/[ \t]*\n/, macros.imports) fContents = fContents.replace(/[ \t]*\/\* \$\{INITIALIZATION\} \*\/[ \t]*\n/, macros.initialization) fContents = fContents.replace(/[ \t]*\/\* \$\{DEFAULTS\} \*\/[ \t]*\n/, macros.defaults) @@ -1263,11 +1279,11 @@ function insertMethodMacros(template, methodObj, json, templates, examples = {}) const resultInit = types.getSchemaShape(flattenedMethod.result.schema, json, { templateDir: 'result-initialization', property: flattenedMethod.result.name, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) // w/out primitive: true, getSchemaShape skips anonymous types, like primitives const serializedEventParams = event ? flattenedMethod.params.filter(p => p.name !== 'listen').map(param => types.getSchemaShape(param.schema, json, {templateDir: 'parameter-serialization', property: param.name, required: param.required, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true })).join('\n') : '' // this was wrong... check when we merge if it was fixed - const callbackSerializedList = event ? types.getSchemaShape(event.result.schema, json, { templateDir: event.params && event.params.length ? 'callback-serialization' : 'callback-result-serialization', property: result.name, required: event.result.schema.required, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) : '' - const callbackInitialization = event ? ((event.params && event.params.length ? (event.params.map(param => types.getSchemaShape(param.schema, json, { templateDir: 'callback-initialization', property: param.name, required: param.required, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true })).join('\n')) + '\n' : '' ) + (types.getSchemaShape(event.result.schema, json, { templateDir: 'callback-initialization', property: result.name, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }))) : '' + const callbackSerializedList = event ? types.getSchemaShape(event.result.schema, json, { templateDir: event.params && event.params.length && !event.tags.find(t => t.name === 'provider') ? 'callback-serialization' : 'callback-result-serialization', property: result.name, required: event.result.schema.required, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) : '' + const callbackInitialization = event ? ((event.params && event.params.length && !event.tags.find(t => t.name === 'provider') ? (event.params.map(param => types.getSchemaShape(param.schema, json, { templateDir: 'callback-initialization', property: param.name, required: param.required, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true })).join('\n')) + '\n' : '' ) + (types.getSchemaShape(event.result.schema, json, { templateDir: 'callback-initialization', property: result.name, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }))) : '' let callbackInstantiation = '' if (event) { - if (event.params && event.params.length) { + if (event.params && event.params.length && !event.tags.find(t => t.name === 'provider')) { callbackInstantiation = types.getSchemaShape(event.result.schema, json, { templateDir: 'callback-instantiation', property: result.name, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) let paramInstantiation = event.params.map(param => types.getSchemaShape(param.schema, json, { templateDir: 'callback-context-instantiation', property: param.name, required: param.required, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true })).join('\n') let resultInstantiation = types.getSchemaShape(event.result.schema, json, { templateDir: 'callback-context-instantiation', property: result.name, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) @@ -1651,38 +1667,113 @@ function insertCapabilityMacros(template, capabilities, method, module) { return content.join() } +function generateProviderSubscribe(json, templates) { + const interfaces = getProvidedCapabilities(json) + const suffix = state.destination ? state.destination.split('.').pop() : '' + let template = getTemplate(suffix ? `/sections/provider-subscribe.${suffix}` : '/sections/provider-subscribe', templates) + const providers = reduce((acc, capability) => { + const template = insertProviderSubscribeMacros(getTemplate(suffix ? `/codeblocks/provider-subscribe.${suffix}` : '/codeblocks/provider-subscribe', templates), capability, json, templates) + return acc + template + }, '', interfaces) + + return interfaces.length ? template.replace(/\$\{providers\.list\}/g, providers) : '' +} + + function generateProviderInterfaces(json, templates) { const interfaces = getProvidedCapabilities(json) - let template = getTemplate('/sections/provider-interfaces', templates) + const suffix = state.destination ? state.destination.split('.').pop() : '' + let template = getTemplate(suffix ? `/sections/provider-interfaces.${suffix}` : '/sections/provider-interfaces', templates) + if (!template) { + template = getTemplate('/sections/provider-interfaces', templates) + } + const providers = reduce((acc, capability) => { - const template = insertProviderInterfaceMacros(getTemplate('/codeblocks/provider', templates), capability, json, templates) + let providerTemplate = getTemplate(suffix ? `/codeblocks/provider.${suffix}` : '/codeblocks/provider', templates) + if (!providerTemplate) { + providerTemplate = getTemplate('/codeblocks/provider', templates) + } + const template = insertProviderInterfaceMacros(providerTemplate, capability, json, templates) return acc + template }, '', interfaces) return interfaces.length ? template.replace(/\$\{providers\.list\}/g, providers) : '' } -function insertProviderInterfaceMacros(template, capability, moduleJson = {}, templates) { - const iface = getProviderInterface(capability, moduleJson, { destination: state.destination, section: state.section })//.map(method => { method.name = method.name.charAt(9).toLowerCase() + method.name.substr(10); return method } ) - +function getProviderInterfaceName(iface, capability, moduleJson = {}) { const uglyName = capability.split(":").slice(-2).map(capitalize).reverse().join('') + "Provider" let name = iface.length === 1 ? iface[0].name.charAt(0).toUpperCase() + iface[0].name.substr(1) + "Provider" : uglyName if (moduleJson.info['x-interface-names']) { name = moduleJson.info['x-interface-names'][capability] || name } + return name +} - let interfaceShape = getTemplate('/codeblocks/interface', templates) +function getProviderXValues(method) { + let xValues = [] + if (method.tags.find(t => t['x-error']) || method.tags.find(t => t['x-response'])) { + method.tags.forEach(tag => { + if (tag['x-response']) { + xValues['x-response'] = tag['x-response'] + } + if (tag['x-error']) { + xValues['x-error'] = tag['x-error'] + } + }) + } + return xValues +} + +function insertProviderXValues(template, moduleJson, xValues) { + if (xValues['x-response']) { + const xResponseInst = types.getSchemaShape(xValues['x-response'], moduleJson, { templateDir: 'parameter-serialization', property: 'result', required: true, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) + template = template.replace(/\$\{provider\.xresponse\.serialization\}/gms, xResponseInst) + .replace(/\$\{provider\.xresponse\.name\}/gms, xValues['x-response'].title) + } + if (xValues['x-error']) { + const xErrorInst = types.getSchemaShape(xValues['x-error'], moduleJson, { templateDir: 'parameter-serialization', property: 'result', required: true, destination: state.destination, section: state.section, primitive: true, skipTitleOnce: true }) + template = template.replace(/\$\{provider\.xerror\.serialization\}/gms, xErrorInst) + .replace(/\$\{provider\.xerror\.name\}/gms, xValues['x-error'].title) + } + return template +} + +function insertProviderSubscribeMacros(template, capability, moduleJson = {}, templates) { + const iface = getProviderInterface(capability, moduleJson, config.extractProviderSchema) + let name = getProviderInterfaceName(iface, capability, moduleJson) + + const suffix = state.destination ? state.destination.split('.').pop() : '' + template = template.replace(/\$\{subscribe\}/gms, iface.map(method => { + return insertMethodMacros(getTemplate(suffix ? `/codeblocks/subscribe.${suffix}` : '/codeblocks/subscribe', templates), method, moduleJson, { destination: state.destination, section: state.section }) + }).join('\n') + '\n') + return template +} + +function insertProviderInterfaceMacros(template, capability, moduleJson = {}, templates) { + const iface = getProviderInterface(capability, moduleJson, config.extractProviderSchema) + let name = getProviderInterfaceName(iface, capability, moduleJson) + let xValues + const suffix = state.destination ? state.destination.split('.').pop() : '' + let interfaceShape = getTemplate(suffix ? `/codeblocks/interface.${suffix}` : '/codeblocks/interface', templates) + if (!interfaceShape) { + interfaceShape = getTemplate('/codeblocks/interface', templates) + } interfaceShape = interfaceShape.replace(/\$\{name\}/g, name) .replace(/\$\{capability\}/g, capability) .replace(/[ \t]*\$\{methods\}[ \t]*\n/g, iface.map(method => { const focusable = method.tags.find(t => t['x-allow-focus']) - const interfaceDeclaration = getTemplate('/interfaces/' + (focusable ? 'focusable' : 'default'), templates) + const interfaceTemplate = '/interfaces/' + (focusable ? 'focusable' : 'default') + const interfaceDeclaration = getTemplate(suffix ? `${interfaceTemplate}.${suffix}` : interfaceTemplate, templates) + xValues = getProviderXValues(method) + method.tags.unshift({ + name: 'provider' + }) return insertMethodMacros(interfaceDeclaration, method, moduleJson, { destination: state.destination, section: state.section, isInterface: true }) }).join('') + '\n') - + if (iface.length === 0) { template = template.replace(/\$\{provider\.methods\}/gms, '') } @@ -1765,6 +1856,7 @@ function insertProviderInterfaceMacros(template, capability, moduleJson = {}, te template = template.replace(/\$\{provider\}/g, name) template = template.replace(/\$\{interface\}/g, interfaceShape) template = template.replace(/\$\{capability\}/g, capability) + template = insertProviderXValues(template, moduleJson, xValues) return template } diff --git a/src/macrofier/index.mjs b/src/macrofier/index.mjs index b3ad15db..f2923717 100644 --- a/src/macrofier/index.mjs +++ b/src/macrofier/index.mjs @@ -54,6 +54,7 @@ const macrofy = async ( additionalSchemaTemplates, additionalMethodTemplates, excludeDeclarations, + extractProviderSchema, aggregateFiles, operators, primitives, @@ -97,6 +98,7 @@ const macrofy = async ( additionalSchemaTemplates, additionalMethodTemplates, excludeDeclarations, + extractProviderSchema, operators }) diff --git a/src/macrofier/types.mjs b/src/macrofier/types.mjs index d587559b..9acc285a 100644 --- a/src/macrofier/types.mjs +++ b/src/macrofier/types.mjs @@ -34,7 +34,7 @@ const stdPrimitives = [ "integer", "number", "boolean", "string" ] const isVoid = type => (type === 'void') ? true : false const isPrimitiveType = type => stdPrimitives.includes(type) ? true : false const allocatedPrimitiveProxies = {} - +const isObject = schema => (schema.type === 'object') || (Array.isArray(schema.type) && schema.type.includes("object")) function setTemplates(t) { Object.assign(templates, t) } @@ -178,8 +178,9 @@ function insertSchemaMacros(content, schema, module, { name = '', parent = '', p .replace(/\$\{if\.namespace\.notsame}(.*?)\$\{end\.if\.namespace\.notsame\}/g, (module.info.title !== (parent || moduleTitle)) ? '$1' : '') .replace(/\$\{parent\.title\}/g, parent || moduleTitle) .replace(/\$\{parent\.Title\}/g, capitalize(parent || moduleTitle)) - .replace(/\$\{if\.optional\}(.*?)\$\{end\.if\.optional\}/gms, (Array.isArray(required) ? required.includes(property) : required) ? '' : '$1') .replace(/\$\{description\}/g, schema.description ? schema.description : '') + .replace(/\$\{if\.optional\}(.*?)\$\{end\.if\.optional\}/gms, (Array.isArray(required) ? required.includes(property) : required) ? '' : '$1') + .replace(/\$\{if\.non.optional\}(.*?)\$\{end\.if\.non.optional\}/gms, (Array.isArray(required) ? required.includes(property) : required) ? '$1' : '') .replace(/\$\{summary\}/g, schema.description ? schema.description.split('\n')[0] : '') .replace(/\$\{name\}/g, title) .replace(/\$\{NAME\}/g, title.toUpperCase()) @@ -261,6 +262,7 @@ const insertObjectAdditionalPropertiesMacros = (content, schema, module, title, .replace(/\$\{delimiter\}(.*?)\$\{end.delimiter\}/g, '') .replace(/\$\{if\.optional\}(.*?)\$\{end\.if\.optional\}/g, '') .replace(/\$\{if\.impl.optional\}(.*?)\$\{end\.if\.impl.optional\}/g, options.required ? '' : '$1') + .replace(/\$\{if\.impl.non.optional\}(.*?)\$\{end\.if\.impl.non.optional\}/g, options.required ? '$1' : '') return content } @@ -303,15 +305,17 @@ const insertObjectMacros = (content, schema, module, title, property, options) = .replace(/\$\{summary\}/g, prop.description ? prop.description.split('\n')[0] : '') .replace(/\$\{delimiter\}(.*?)\$\{end.delimiter\}/gms, i === schema.properties.length - 1 ? '' : '$1') .replace(/\$\{if\.optional\}(.*?)\$\{end\.if\.optional\}/gms, schema.required && schema.required.includes(name) ? '' : '$1') + .replace(/\$\{if\.non.optional\}(.*?)\$\{end\.if\.non.optional\}/gms, schema.required && schema.required.includes(name) ? '$1' : '') .replace(/\$\{if\.base\.optional\}(.*?)\$\{end\.if\.base\.optional\}/gms, options.required ? '' : '$1') - .replace(/\$\{if\.non\.object\}(.*?)\$\{end\.if\.non\.object\}/gms, (localizedProp.type === 'object') ? '' : '$1') + .replace(/\$\{if\.non\.object\}(.*?)\$\{end\.if\.non\.object\}/gms, isObject(localizedProp) ? '' : '$1') .replace(/\$\{if\.non\.array\}(.*?)\$\{end\.if\.non\.array\}/gms, (localizedProp.type === 'array') ? '' : '$1') .replace(/\$\{if\.non\.anyOf\}(.*?)\$\{end\.if\.non\.anyOf\}/gms, (localizedProp.anyOf || localizedProp.anyOneOf) ? '' : '$1') .replace(/\$\{if\.non\.const\}(.*?)\$\{end\.if\.non\.const\}/gms, (typeof localizedProp.const === 'string') ? '' : '$1') let baseTitle = options.property - if (localizedProp.type === 'object') { + if (isObject(localizedProp)) { replacedTemplate = replacedTemplate .replace(/\$\{if\.impl.optional\}(.*?)\$\{end\.if\.impl.optional\}/gms, schema.required && schema.required.includes(name) ? '' : '$1') + .replace(/\$\{if\.impl.non.optional\}(.*?)\$\{end\.if\.impl.non.optional\}/gms, schema.required && schema.required.includes(name) ? '$1' : '') .replace(/\$\{property.dependency\}/g, ((options.level > 0) ? '${property.dependency}${if.impl.optional}.value()${end.if.impl.optional}' : '') + objSeparator + name) .replace(/\$\{Property.dependency\}/g, ((options.level > 0) ? '${Property.dependency}' : '') + capitalize(name) + (objSeparator)) } @@ -368,7 +372,8 @@ const insertObjectMacros = (content, schema, module, title, property, options) = .replace(/\$\{description\}/g, prop.description || '') .replace(/\$\{summary\}/g, prop.description ? prop.description.split('\n')[0] : '') .replace(/\$\{delimiter\}(.*?)\$\{end.delimiter\}/gms, i === propertyNames.enum.length - 1 ? '' : '$1') - .replace(/\$\{if\.optional\}(.*?)\$\{end\.if\.optional\}/gms, schema.required && schema.required.includes(prop) ? '' : '$1')) + .replace(/\$\{if\.optional\}(.*?)\$\{end\.if\.optional\}/gms, schema.required && schema.required.includes(prop) ? '' : '$1') + .replace(/\$\{if\.non.optional\}(.*?)\$\{end\.if\.non.optional\}/gms, schema.required && schema.required.includes(prop) ? '$1' : '')) } }) } @@ -392,8 +397,9 @@ const insertArrayMacros = (content, schema, module, level = 0, items, required = content = content .replace(/\$\{json\.type\}/g, getSchemaType(schema.items, module, { templateDir: 'json-types', destination: state.destination, section: state.section, code: false, namespace: true })) .replace(/\$\{items\}/g, items) - .replace(/\$\{items\.with\.indent\}/g, indent(items, ' ')) + .replace(/\$\{items\.with\.indent\}/g, required ? indent(items, ' ') : indent(items, ' ')) .replace(/\$\{if\.impl.array.optional\}(.*?)\$\{end\.if\.impl.array.optional\}/gms, required ? '' : '$1') + .replace(/\$\{if\.impl.array.non.optional\}(.*?)\$\{end\.if\.impl.array.non.optional\}/gms, required ? '$1' : '') return content } @@ -511,7 +517,7 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', paren result = result.replace(/\$\{shape\}/g, shape) return insertSchemaMacros(result, schema, module, { name: theTitle, parent, property, required }) } - else if (schema.type === 'object') { + else if (isObject(schema)) { let shape const additionalPropertiesTemplate = getTemplate(path.join(templateDir, 'additionalProperties')) if (additionalPropertiesTemplate && schema.additionalProperties && (typeof schema.additionalProperties === 'object')) { @@ -524,6 +530,7 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', paren result = result.replace(/\$\{shape\}/g, shape) if (level === 0) { result = result.replace(/\$\{if\.impl.optional\}(.*?)\$\{end\.if\.impl.optional\}/gms, (Array.isArray(required) ? required.includes(property) : required) ? '' : '$1') + result = result.replace(/\$\{if\.impl.non.optional\}(.*?)\$\{end\.if\.impl.non.optional\}/gms, (Array.isArray(required) ? required.includes(property) : required) ? '$1' : '') } return insertSchemaMacros(result, schema, module, { name: theTitle, parent, property, required, templateDir }) } @@ -583,7 +590,7 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', paren const items = getSchemaShape(schema.items, module, { templateDir, parent, property, required, parentLevel: parentLevel + 1, level, summary, descriptions, destination, enums: false, array: true, primitive }) const shape = insertArrayMacros(getTemplate(path.join(templateDir, 'array' + suffix)) || genericTemplate, schema, module, level, items, Array.isArray(required) ? required.includes(property) : required) result = result.replace(/\$\{shape\}/g, shape) - .replace(/\$\{if\.object\}(.*?)\$\{end\.if\.object\}/gms, (schema.items.type === 'object') ? '$1' : '') + .replace(/\$\{if\.object\}(.*?)\$\{end\.if\.object\}/gms, isObject(schema.items) ? '$1' : '') .replace(/\$\{if\.non\.object\}(.*?)\$\{end\.if\.non\.object\}/gms, (schema.items.type !== 'object') ? '$1' : '') return insertSchemaMacros(result, schema, module, { name: items, parent, property, required, templateDir }) } @@ -656,7 +663,7 @@ function getSchemaType(schema, module, { destination, templateDir = 'types', lin const theTitle = insertSchemaMacros(namespaceStr + getTemplate(path.join(templateDir, 'title' + suffix)), schema, module, { name: schema.title, parent: getXSchemaGroup(schema, module), recursive: false }) const allocatedProxy = event || result - const title = schema.type === "object" || schema.enum ? true : false + const title = schema.type === "object" || Array.isArray(schema.type) && schema.type.includes("object") || schema.enum ? true : false if (schema['$ref']) { if (schema['$ref'][0] === '#') { @@ -811,7 +818,12 @@ function getSchemaType(schema, module, { destination, templateDir = 'types', lin } } else { - const template = getTemplate(path.join(templateDir, 'void')) || 'void' + let type + if (schema.title) { + const baseDir = (templateDir !== 'json-types' ? 'types': templateDir) + type = getPrimitiveType('string', baseDir) + } + const template = type || getTemplate(path.join(templateDir, 'void')) || 'void' // TODO this is TypeScript specific return wrap(template, code ? '`' : '') } diff --git a/src/sdk/index.mjs b/src/sdk/index.mjs index 763b6c9e..627e3346 100755 --- a/src/sdk/index.mjs +++ b/src/sdk/index.mjs @@ -70,6 +70,7 @@ const run = async ({ additionalSchemaTemplates: config.additionalSchemaTemplates, additionalMethodTemplates: config.additionalMethodTemplates, excludeDeclarations: config.excludeDeclarations, + extractProviderSchema: config.extractProviderSchema, staticModuleNames: staticModuleNames, hideExcluded: true, aggregateFiles: config.aggregateFiles, diff --git a/src/shared/modules.mjs b/src/shared/modules.mjs index 355da86c..c55d5af4 100644 --- a/src/shared/modules.mjs +++ b/src/shared/modules.mjs @@ -85,7 +85,7 @@ const getProviderInterfaceMethods = (capability, json) => { } -function getProviderInterface(capability, module) { +function getProviderInterface(capability, module, extractProviderSchema = false) { module = JSON.parse(JSON.stringify(module)) const iface = getProviderInterfaceMethods(capability, module).map(method => localizeDependencies(method, module, null, { mergeAllOfs: true })) @@ -95,62 +95,63 @@ function getProviderInterface(capability, module) { // remove `onRequest` method.name = method.name.charAt(9).toLowerCase() + method.name.substr(10) + + method.params = [ + { + "name": "parameters", + "required": true, + "schema": payload.properties.parameters + } + ] - method.params = [ - { - "name": "parameters", - "required": true, - "schema": payload.properties.parameters - } - ] - - let exampleResult = null - - if (method.tags.find(tag => tag['x-response'])) { - const result = method.tags.find(tag => tag['x-response'])['x-response'] + if (!extractProviderSchema) { + let exampleResult = null + + if (method.tags.find(tag => tag['x-response'])) { + const result = method.tags.find(tag => tag['x-response'])['x-response'] - method.result = { - "name": "result", - "schema": result - } + method.result = { + "name": "result", + "schema": result + } - if (result.examples && result.examples[0]) { - exampleResult = result.examples[0] + if (result.examples && result.examples[0]) { + exampleResult = result.examples[0] + } } - } - else { - method.result = { - "name": "result", - "schema": { - "const": null + else { + method.result = { + "name": "result", + "schema": { + "const": null + } } } - } - method.examples = method.examples.map( example => ( - { - params: [ - { - name: "parameters", - value: example.result.value.parameters - }, - { - name: "correlationId", - value: example.result.value.correlationId + method.examples = method.examples.map( example => ( + { + params: [ + { + name: "parameters", + value: example.result.value.parameters + }, + { + name: "correlationId", + value: example.result.value.correlationId + } + ], + result: { + name: "result", + value: exampleResult } - ], - result: { - name: "result", - value: exampleResult } - } - )) + )) - // remove event tag - method.tags = method.tags.filter(tag => tag.name !== 'event') + // remove event tag + method.tags = method.tags.filter(tag => tag.name !== 'event') + } }) - return iface }