Skip to content

Commit

Permalink
Generate polymorphci methods for anyOf param/result case (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
HaseenaSainul committed Jul 17, 2023
1 parent ffd97fd commit 549e4a0
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 28 deletions.
1 change: 1 addition & 0 deletions languages/c/Types.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ function getSchemaTypeInfo(module = {}, json = {}, name = '', schemas = {}, pref
structure.namespace = getModuleName(module)
}
}

return structure
}

Expand Down
3 changes: 2 additions & 1 deletion languages/c/language.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@
"/src/module_common.cpp",
"/src/jsondata_module.h"
],
"persistPermission": true
"persistPermission": true,
"createPolymorphicMethods": true
}
4 changes: 2 additions & 2 deletions languages/c/templates/codeblocks/setter.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* ${method.name} - ${method.description} */
/* ${method.rpc.name} - ${method.description} */
uint32_t ${info.Title}_${method.Name}( ${method.signature.params} )
{
const string method = _T("${info.title}.${method.name}");
const string method = _T("${info.title.lowercase}.${method.rpc.name}");
${if.params}${method.params.serialization}${end.if.params}
return FireboltSDK::Properties::Set(method, jsonParameters);
}
6 changes: 3 additions & 3 deletions languages/c/templates/methods/default.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* ${method.name} - ${method.description} */
/* ${method.rpc.name} - ${method.description} */
uint32_t ${info.Title}_${method.Name}( ${method.signature.params}${if.result}${if.params}, ${end.if.params}${method.result.type}* ${method.result.name}${end.if.result}${if.signature.empty}void${end.if.signature.empty} ) {

uint32_t status = FireboltSDKErrorUnavailable;
Expand All @@ -7,9 +7,9 @@ uint32_t ${info.Title}_${method.Name}( ${method.signature.params}${if.result}${i

${method.params.serialization.with.indent}
${method.result.json.type} jsonResult;
status = transport->Invoke("${info.title}.${method.name}", jsonParameters, jsonResult);
status = transport->Invoke("${info.title.lowercase}.${method.rpc.name}", jsonParameters, jsonResult);
if (status == FireboltSDKErrorNone) {
FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module<FireboltSDK::Accessor>(), "${info.Title}.${method.name} is successfully invoked");
FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module<FireboltSDK::Accessor>(), "${info.Title}.${method.rpc.name} is successfully invoked");
${method.result.instantiation}
}

Expand Down
6 changes: 3 additions & 3 deletions languages/c/templates/methods/event.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* ${method.name} - ${method.description} */
/* ${method.rpc.name} - ${method.description} */
static void ${info.Title}${method.Name}InnerCallback( void* userCB, const void* userData, void* response )
{
${event.callback.params.serialization}
Expand All @@ -11,7 +11,7 @@ static void ${info.Title}${method.Name}InnerCallback( void* userCB, const void*
}
uint32_t ${info.Title}_Register_${method.Name}( ${event.signature.params}${if.event.params}, ${end.if.event.params}${info.Title}${method.Name}Callback userCB, const void* userData )
{
const string eventName = _T("${info.title}.${method.name}");
const string eventName = _T("${info.title.lowercase}.${method.rpc.name}");
uint32_t status = FireboltSDKErrorNone;

if (userCB != nullptr) {
Expand All @@ -22,5 +22,5 @@ uint32_t ${info.Title}_Register_${method.Name}( ${event.signature.params}${if.ev
}
uint32_t ${info.Title}_Unregister_${method.Name}( ${info.Title}${method.Name}Callback userCB)
{
return FireboltSDK::Event::Instance().Unsubscribe(_T("${info.title}.${method.name}"), reinterpret_cast<void*>(userCB));
return FireboltSDK::Event::Instance().Unsubscribe(_T("${info.title.lowercase}.${method.rpc.name}"), reinterpret_cast<void*>(userCB));
}
10 changes: 5 additions & 5 deletions languages/c/templates/methods/polymorphic-pull-event.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* ${method.name} - ${method.description} */
/* ${method.rpc.name} - ${method.description} */
static void ${info.Title}${method.Name}InnerCallback( void* userCB, const void* userData, void* response )
{
${event.callback.params.serialization}
Expand Down Expand Up @@ -27,9 +27,9 @@ static void ${info.Title}${method.Name}InnerCallback( void* userCB, const void*
FireboltSDK::Transport<WPEFramework::Core::JSON::IElement>* transport = FireboltSDK::Accessor::Instance().GetTransport();
if (transport != nullptr) {
WPEFramework::Core::JSON::Boolean jsonResult;
uint32_t status = transport->Invoke(_T("${info.title}.${method.pulls.for}"), jsonParameters, jsonResult);
uint32_t status = transport->Invoke(_T("${info.title.lowercase}.${method.pulls.for}"), jsonParameters, jsonResult);
if (status == FireboltSDKErrorNone) {
FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module<FireboltSDK::Accessor>(), "${info.Title}.${method.name} is successfully pushed with status as %d", jsonResult.Value());
FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module<FireboltSDK::Accessor>(), "${info.Title}.${method.rpc.name} is successfully pushed with status as %d", jsonResult.Value());
status = (jsonResult.Value() == true) ? FireboltSDKErrorNone : FireboltSDKErrorNotSupported;
}
} else {
Expand All @@ -39,7 +39,7 @@ static void ${info.Title}${method.Name}InnerCallback( void* userCB, const void*
}
uint32_t ${info.Title}_Register_${method.Name}( ${info.Title}${method.Name}Callback userCB, const void* userData )
{
const string eventName = _T("${info.title}.${method.name}");
const string eventName = _T("${info.title.lowercase}.${method.rpc.name}");
uint32_t status = FireboltSDKErrorNone;

if (userCB != nullptr) {
Expand All @@ -50,5 +50,5 @@ uint32_t ${info.Title}_Register_${method.Name}( ${info.Title}${method.Name}Callb
}
uint32_t ${info.Title}_Unregister_${method.Name}( ${info.Title}${method.Name}Callback userCB)
{
return FireboltSDK::Event::Instance().Unsubscribe(_T("${info.title}.${method.name}"), reinterpret_cast<void*>(userCB));
return FireboltSDK::Event::Instance().Unsubscribe(_T("${info.title.lowercase}.${method.rpc.name}"), reinterpret_cast<void*>(userCB));
}
11 changes: 6 additions & 5 deletions languages/c/templates/methods/polymorphic-pull.c
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/* ${method.name} - ${method.description} */
/* ${method.rpc.name} - ${method.description} */
uint32_t ${info.Title}_Push${method.Name}( ${method.signature.params} )
{
uint32_t status = FireboltSDKErrorUnavailable;

string correlationId = "";
${method.params.serialization}
FireboltSDK::Transport<WPEFramework::Core::JSON::IElement>* transport = FireboltSDK::Accessor::Instance().GetTransport();
if (transport != nullptr) {
string correlationId = "";
${method.params.serialization.with.indent}

WPEFramework::Core::JSON::Boolean jsonResult;
status = transport->Invoke(_T("${info.title}.${method.name}"), jsonParameters, jsonResult);
status = transport->Invoke(_T("${info.title.lowercase}.${method.rpc.name}"), jsonParameters, jsonResult);
if (status == FireboltSDKErrorNone) {
FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module<FireboltSDK::Accessor>(), "${info.Title}.${method.name} is successfully pushed with status as %d", jsonResult.Value());
FIREBOLT_LOG_INFO(FireboltSDK::Logger::Category::OpenRPC, FireboltSDK::Logger::Module<FireboltSDK::Accessor>(), "${info.Title}.${method.rpc.name} is successfully pushed with status as %d", jsonResult.Value());
status = (jsonResult.Value() == true) ? FireboltSDKErrorNone : FireboltSDKErrorNotSupported;
}
} else {
Expand Down
4 changes: 2 additions & 2 deletions languages/c/templates/methods/property.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* ${method.name} - ${method.description} */
/* ${method.rpc.name} - ${method.description} */
uint32_t ${info.Title}_Get${method.Name}( ${method.signature.params}${if.params}, ${end.if.params}${method.result.type}* ${method.result.name} )
{
const string method = _T("${info.title}.${method.name}");
const string method = _T("${info.title.lowercase}.${method.rpc.name}");
${if.params}${method.params.serialization}${end.if.params}
${method.result.json} jsonResult;
${if.params}uint32_t status = FireboltSDK::Properties::Get(method, jsonParameters, jsonResult);${end.if.params}
Expand Down
20 changes: 18 additions & 2 deletions src/macrofier/engine.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import isString from 'crocks/core/isString.js'
import predicates from 'crocks/predicates/index.js'
const { isObject, isArray, propEq, pathSatisfies, propSatisfies } = predicates

import { isRPCOnlyMethod, isProviderInterfaceMethod, getProviderInterface, getPayloadFromEvent, providerHasNoParameters, isTemporalSetMethod, isCallsMetricsMethod, isExcludedMethod, hasMethodAttributes, getMethodAttributes, isEventMethodWithContext, getSemanticVersion, getSetterFor, getProvidedCapabilities, isPolymorphicPullMethod, hasPublicAPIs } from '../shared/modules.mjs'
import { isRPCOnlyMethod, isProviderInterfaceMethod, getProviderInterface, getPayloadFromEvent, providerHasNoParameters, isTemporalSetMethod, hasMethodAttributes, getMethodAttributes, isEventMethodWithContext, getSemanticVersion, getSetterFor, getProvidedCapabilities, isPolymorphicPullMethod, hasPublicAPIs, createPolymorphicMethods } from '../shared/modules.mjs'
import isEmpty from 'crocks/core/isEmpty.js'
import { getLinkedSchemaPaths, getSchemaConstraints, isSchema, localizeDependencies, isDefinitionReferencedBySchema } from '../shared/json-schema.mjs'

Expand Down Expand Up @@ -416,6 +416,21 @@ const generateMacros = (obj, templates, languages, options = {}) => {
if (config.extractSubSchemas) {
obj = promoteAndNameSubSchemas(obj)
}
if (options.createPolymorphicMethods) {
let methods = []
obj.methods && obj.methods.forEach(method => {
let polymorphicMethods = createPolymorphicMethods(method, obj)
if (polymorphicMethods.length > 1) {
polymorphicMethods.forEach(polymorphicMethod => {
methods.push(polymorphicMethod)
})
}
else {
methods.push(method)
}
})
obj.methods = methods
}

// grab the options so we don't have to pass them from method to method
Object.assign(state, options)
Expand Down Expand Up @@ -1022,7 +1037,7 @@ function generateMethods(json = {}, examples = {}, templates = {}) {
}

// TODO: this is called too many places... let's reduce that to just generateMethods
function insertMethodMacros(template, methodObj, json, templates, examples = {}) {
function insertMethodMacros(template, methodObj, json, templates, examples={}) {
const moduleName = getModuleName(json)

const info = {
Expand Down Expand Up @@ -1131,6 +1146,7 @@ function insertMethodMacros(template, methodObj, json, templates, examples = {})
template = insertExampleMacros(template, examples[methodObj.name] || [], methodObj, json, templates)

template = template.replace(/\$\{method\.name\}/g, method.name)
.replace(/\$\{method\.rpc\.name\}/g, methodObj.title || methodObj.name)
.replace(/\$\{method\.summary\}/g, methodObj.summary)
.replace(/\$\{method\.description\}/g, methodObj.description
|| methodObj.summary)
Expand Down
7 changes: 4 additions & 3 deletions src/macrofier/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const macrofy = async (
templatesPerModule,
templatesPerSchema,
persistPermission,
createPolymorphicMethods,
createModuleDirectories,
copySchemasIntoModules,
extractSubSchemas,
Expand Down Expand Up @@ -159,7 +160,7 @@ const macrofy = async (

// Pick the index and defaults templates for each module.
templatesPerModule.forEach(t => {
const macros = engine.generateMacros(module, templates, exampleTemplates, {hideExcluded: hideExcluded, copySchemasIntoModules: copySchemasIntoModules, destination: t})
const macros = engine.generateMacros(module, templates, exampleTemplates, {hideExcluded: hideExcluded, copySchemasIntoModules: copySchemasIntoModules, createPolymorphicMethods: createPolymorphicMethods, destination: t})
let content = getTemplateForModule(module.info.title, t, templates)

// NOTE: whichever insert is called first also needs to be called again last, so each phase can insert recursive macros from the other
Expand All @@ -174,7 +175,7 @@ const macrofy = async (
})

if (primaryOutput) {
const macros = engine.generateMacros(module, templates, exampleTemplates, {hideExcluded: hideExcluded, copySchemasIntoModules: copySchemasIntoModules, destination: primaryOutput})
const macros = engine.generateMacros(module, templates, exampleTemplates, {hideExcluded: hideExcluded, copySchemasIntoModules: copySchemasIntoModules, createPolymorphicMethods: createPolymorphicMethods, destination: primaryOutput})
macros.append = append
outputFiles[primaryOutput] = engine.insertMacros(outputFiles[primaryOutput], macros)
}
Expand Down Expand Up @@ -256,7 +257,7 @@ const macrofy = async (
Object.values(externalSchemas).forEach( document => {
if (templatesPerSchema) {
templatesPerSchema.forEach( t => {
const macros = engine.generateMacros(document, templates, exampleTemplates, {hideExcluded: hideExcluded, destination: t})
const macros = engine.generateMacros(document, templates, exampleTemplates, {hideExcluded: hideExcluded, createPolymorphicMethods: createPolymorphicMethods, destination: t})
let content = getTemplate('/schemas', t, templates)

// NOTE: whichever insert is called first also needs to be called again last, so each phase can insert recursive macros from the other
Expand Down
1 change: 1 addition & 0 deletions src/sdk/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const run = async ({
templatesPerModule: config.templatesPerModule,
templatesPerSchema: config.templatesPerSchema,
persistPermission: config.persistPermission,
createPolymorphicMethods: config.createPolymorphicMethods,
operators: config.operators,
createModuleDirectories: config.createModuleDirectories,
copySchemasIntoModules: config.copySchemasIntoModules,
Expand Down
137 changes: 135 additions & 2 deletions src/shared/modules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const { and, not } = logic
import isString from 'crocks/core/isString.js'
import predicates from 'crocks/predicates/index.js'
import { getExternalSchemaPaths, isDefinitionReferencedBySchema, isNull, localizeDependencies, isSchema, getLocalSchemaPaths, replaceRef } from './json-schema.mjs'
import { getPath as getRefDefinition } from './json-schema.mjs'
const { isObject, isArray, propEq, pathSatisfies, hasProp, propSatisfies } = predicates

// util for visually debugging crocks ADTs
Expand Down Expand Up @@ -861,6 +862,137 @@ const generateEventListenResponse = json => {
return json
}

const getAnyOfSchema = (inType, json) => {
let anyOfTypes = []
let outType = localizeDependencies(inType, json)
if (outType.schema.anyOf) {
let definition = ''
if (inType.schema['$ref'] && (inType.schema['$ref'][0] === '#')) {
definition = getRefDefinition(inType.schema['$ref'], json, json['x-schemas'])
}
else {
definition = outType.schema
}
definition.anyOf.forEach(anyOf => {
anyOfTypes.push(anyOf)
})
outType.schema.anyOf = anyOfTypes
}
return outType
}

const generateAnyOfSchema = (anyOf, name, summary) => {
let anyOfType = {}
anyOfType["name"] = name[0].toLowerCase() + name.substr(1)
anyOfType["summary"] = summary
anyOfType["schema"] = anyOf
return anyOfType
}

const generateParamsAnyOfSchema = (methodParams, anyOf, anyOfTypes, title, summary) => {
let params = []
methodParams.forEach(p => {
if (p.schema.anyOf === anyOfTypes) {
let anyOfType = generateAnyOfSchema(anyOf, title, summary)
anyOfType.required = p.required
params.push(anyOfType)
}
else {
params.push(p)
}
})
return params
}

const generateResultAnyOfSchema = (method, methodResult, anyOf, anyOfTypes, title, summary) => {
let methodResultSchema = {}
if (methodResult.schema.anyOf === anyOfTypes) {
let anyOfType = generateAnyOfSchema(anyOf, title, summary)
let index = 0
if (isEventMethod(method)) {
index = (method.result.schema.anyOf || method.result.schema.oneOf).indexOf(getPayloadFromEvent(method))
}
else {
index = (method.result.schema.anyOf || method.result.schema.oneOf).indexOf(anyOfType)
}
if (method.result.schema.anyOf) {
methodResultSchema["anyOf"] = Object.assign([], method.result.schema.anyOf)
methodResultSchema.anyOf[index] = anyOfType.schema
}
else if (method.result.schema.oneOf) {
methodResultSchema["oneOf"] = Object.assign([], method.result.schema.oneOf)
methodResultSchema.oneOf[index] = anyOfType.schema
}
else {
methodResultSchema = anyOfType.schema
}
}
return methodResultSchema
}

const createPolymorphicMethods = (method, json) => {
let anyOfTypes
let methodParams = []
let methodResult = Object.assign({}, method.result)
method.params.forEach(p => {
if (p.schema) {
let param = getAnyOfSchema(p, json)
if (param.schema.anyOf && anyOfTypes) {
//anyOf is allowed with only one param in the params list
throw `WARNING anyOf is repeated with param:${p}`
}
else if (param.schema.anyOf) {
anyOfTypes = param.schema.anyOf
}
methodParams.push(param)
}
})
let foundAnyOfParams = anyOfTypes ? true : false

if (isEventMethod(method)) {
methodResult.schema = getPayloadFromEvent(method)
}
methodResult = getAnyOfSchema(methodResult, json)
let foundAnyOfResult = methodResult.schema.anyOf ? true : false
if (foundAnyOfParams === true && foundAnyOfResult === true) {
throw `WARNING anyOf is already with param schema, it is repeated with ${method.name} result too`
}
else if (foundAnyOfResult === true) {
anyOfTypes = methodResult.schema.anyOf
}
let polymorphicMethodSchemas = []
//anyOfTypes will be allowed either in any one of the params or in result
if (anyOfTypes) {
let polymorphicMethodSchema = {
name: {},
tags: {},
summary: `${method.summary}`,
params: {},
result: {},
examples: {}
}
anyOfTypes.forEach(anyOf => {

let localized = localizeDependencies(anyOf, json)
let title = localized.title || localized.name || ''
let summary = localized.summary || localized.description || ''
polymorphicMethodSchema.title = method.name
polymorphicMethodSchema.name = foundAnyOfParams ? `${method.name}With${title}` : `${method.name}${title}`
polymorphicMethodSchema.tags = method.tags
polymorphicMethodSchema.params = foundAnyOfParams ? generateParamsAnyOfSchema(methodParams, anyOf, anyOfTypes, title, summary) : methodParams
polymorphicMethodSchema.result = Object.assign({}, method.result)
polymorphicMethodSchema.result.schema = foundAnyOfResult ? generateResultAnyOfSchema(method, methodResult, anyOf, anyOfTypes, title, summary) : methodResult
polymorphicMethodSchema.examples = method.examples
polymorphicMethodSchemas.push(Object.assign({}, polymorphicMethodSchema))
})
}
else {
polymorphicMethodSchemas = method
}

return polymorphicMethodSchemas
}

const getPathFromModule = (module, path) => {
console.error("DEPRECATED: getPathFromModule")

Expand Down Expand Up @@ -1183,5 +1315,6 @@ export {
getSemanticVersion,
addExternalMarkdown,
addExternalSchemas,
getExternalMarkdownPaths
}
getExternalMarkdownPaths,
createPolymorphicMethods
}

0 comments on commit 549e4a0

Please sign in to comment.