From 310803d22fc087d962e40730eae6aa4500a35315 Mon Sep 17 00:00:00 2001 From: HaseenaSainul Date: Fri, 6 Oct 2023 02:28:16 -0400 Subject: [PATCH 1/4] CPPSDK: changes to handle enum and x-schema enum without title --- src/macrofier/engine.mjs | 4 ++-- src/macrofier/types.mjs | 16 ++++++++++------ src/shared/modules.mjs | 5 +++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index b1d2dd89..0b8a4aec 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -727,7 +727,7 @@ const convertEnumTemplate = (schema, templateName, templates) => { const template = getTemplate(templateName, templates).split('\n') for (var i = 0; i < template.length; i++) { if (template[i].indexOf('${key}') >= 0) { - template[i] = enumSchema.enum.map(value => { + template[i] = enumSchema.enum.filter(value => value).map(value => { const safeName = value.split(':').pop().replace(/[\.\-]/g, '_').replace(/\+/g, '_plus').replace(/([a-z])([A-Z0-9])/g, '$1_$2').toUpperCase() return template[i].replace(/\$\{key\}/g, safeName) .replace(/\$\{value\}/g, value) @@ -887,7 +887,7 @@ function generateSchemas(json, templates, options) { } content = content.trim().length ? content : content.trim() - const isEnum = x => x.type === 'string' && Array.isArray(x.enum) && x.title + const isEnum = x => x.type && Array.isArray(x.enum) && x.title && ((x.type === 'string') || (x.type[0] === 'string')) const result = uri ? { uri: uri, diff --git a/src/macrofier/types.mjs b/src/macrofier/types.mjs index 6ee24f2a..39ca82ba 100644 --- a/src/macrofier/types.mjs +++ b/src/macrofier/types.mjs @@ -157,15 +157,18 @@ const insertConstMacros = (content, schema, module, name) => { return content } -const insertEnumMacros = (content, schema, module, name) => { +const insertEnumMacros = (content, schema, module, name, suffix) => { const template = content.split('\n') for (var i = 0; i < template.length; i++) { if (template[i].indexOf('${key}') >= 0) { - template[i] = schema.enum.map(value => { + template[i] = schema.enum.filter(value => value).map(value => { return template[i].replace(/\$\{key\}/g, safeName(value)) .replace(/\$\{value\}/g, value) }).join('\n') + if (suffix !== ".cpp") { + template[i] = template[i].replace(/,*$/, ''); + } } } @@ -377,15 +380,15 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name let result = level === 0 ? getTemplate(path.join(templateDir, 'default' + suffix)) : '${shape}' - if (enums && level === 0 && schema.type === "string" && Array.isArray(schema.enum)) { + if (enums && level === 0 && Array.isArray(schema.enum) && ((schema.type === "string") || (schema.type[0] === "string"))) { result = getTemplate(path.join(templateDir, 'enum' + suffix)) - return insertSchemaMacros(insertEnumMacros(result, schema, module, theTitle), schema, module, theTitle, parent, property) + return insertSchemaMacros(insertEnumMacros(result, schema, module, theTitle, suffix), schema, module, theTitle, parent, property) } if (schema['$ref']) { const someJson = getPath(schema['$ref'], module) if (someJson) { - return getSchemaShape(someJson, module, { templateDir, name, parent, property, level, summary, descriptions, destination, enums: false }) + return getSchemaShape(someJson, module, { templateDir, name, parent, property, level, summary, descriptions, destination, enums }) } throw "Unresolvable $ref: " + schema['ref'] + ", in " + module.info.title } @@ -395,8 +398,9 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name return result } else if (!skipTitleOnce && (level > 0) && schema.title) { + let enumType = (schema.type === 'string' && Array.isArray(schema.enum)) // TODO: allow the 'ref' template to actually insert the shape using getSchemaShape - const innerShape = getSchemaShape(schema, module, { skipTitleOnce: true, templateDir, name, parent, property, level, summary, descriptions, destination, enums: false }) + const innerShape = getSchemaShape(schema, module, { skipTitleOnce: true, templateDir, name, parent, property, level, summary, descriptions, destination, enums: enumType }) const shape = getTemplate(path.join(templateDir, 'ref' + suffix)) .replace(/\$\{shape\}/g, innerShape) diff --git a/src/shared/modules.mjs b/src/shared/modules.mjs index ed0f474a..9f85bb1d 100644 --- a/src/shared/modules.mjs +++ b/src/shared/modules.mjs @@ -1224,6 +1224,11 @@ const getModule = (name, json, copySchemas) => { ...(openrpc[destination[0]][destination[1]][destination[2]] || {}) } } + const capitalize = str => str[0].toUpperCase() + str.substr(1) + if (!schema.title) { + schema.title = capitalize(parts.pop()) + } + openrpc = setPath(destination, schema, openrpc) } }) From fb5d8af177209af5665f646868e39aab061ebb50 Mon Sep 17 00:00:00 2001 From: HaseenaSainul Date: Tue, 10 Oct 2023 02:22:11 -0400 Subject: [PATCH 2/4] CPPSDK: review comments updated --- languages/cpp/language.config.json | 1 + src/macrofier/engine.mjs | 2 +- src/macrofier/index.mjs | 2 ++ src/macrofier/types.mjs | 12 ++++++------ src/sdk/index.mjs | 1 + 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/languages/cpp/language.config.json b/languages/cpp/language.config.json index debc539d..541f0258 100644 --- a/languages/cpp/language.config.json +++ b/languages/cpp/language.config.json @@ -6,6 +6,7 @@ "unwrapResultObjects": false, "createPolymorphicMethods": true, "excludeDeclarations":true, + "enumSuffix": ".cpp", "aggregateFiles": [ "/include/firebolt.h", "/src/firebolt.cpp" diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index 0b8a4aec..7fda8cce 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -867,7 +867,7 @@ function generateSchemas(json, templates, options) { else { content = content.replace(/\$\{if\.description\}(.*?)\{end\.if\.description\}/gms, '$1') } - const schemaShape = types.getSchemaShape(schema, json, { templateDir: state.typeTemplateDir, destination: state.destination, section: options.section }) + const schemaShape = types.getSchemaShape(schema, json, { templateDir: state.typeTemplateDir, destination: state.destination, section: options.section, enumSuffix: config.enumSuffix }) content = content .replace(/\$\{schema.title\}/, (schema.title || name)) diff --git a/src/macrofier/index.mjs b/src/macrofier/index.mjs index 04cdd9fb..6550a9b6 100644 --- a/src/macrofier/index.mjs +++ b/src/macrofier/index.mjs @@ -54,6 +54,7 @@ const macrofy = async ( additionalSchemaTemplates, additionalMethodTemplates, excludeDeclarations, + enumSuffix, aggregateFiles, operators, primitives, @@ -97,6 +98,7 @@ const macrofy = async ( additionalSchemaTemplates, additionalMethodTemplates, excludeDeclarations, + enumSuffix, operators }) diff --git a/src/macrofier/types.mjs b/src/macrofier/types.mjs index 39ca82ba..275da98d 100644 --- a/src/macrofier/types.mjs +++ b/src/macrofier/types.mjs @@ -157,7 +157,7 @@ const insertConstMacros = (content, schema, module, name) => { return content } -const insertEnumMacros = (content, schema, module, name, suffix) => { +const insertEnumMacros = (content, schema, module, name, suffix, enumSuffix) => { const template = content.split('\n') for (var i = 0; i < template.length; i++) { @@ -166,7 +166,7 @@ const insertEnumMacros = (content, schema, module, name, suffix) => { return template[i].replace(/\$\{key\}/g, safeName(value)) .replace(/\$\{value\}/g, value) }).join('\n') - if (suffix !== ".cpp") { + if (suffix !== enumSuffix) { template[i] = template[i].replace(/,*$/, ''); } } @@ -365,7 +365,7 @@ const sanitize = (schema) => { return result } -function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name = '', parent = '', property = '', level = 0, summary, descriptions = true, destination, section, enums = true, skipTitleOnce = false } = {}) { +function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name = '', parent = '', property = '', level = 0, summary, descriptions = true, destination, section, enums = true, enumSuffix = '', skipTitleOnce = false } = {}) { schema = sanitize(schema) state.destination = destination @@ -382,13 +382,13 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name if (enums && level === 0 && Array.isArray(schema.enum) && ((schema.type === "string") || (schema.type[0] === "string"))) { result = getTemplate(path.join(templateDir, 'enum' + suffix)) - return insertSchemaMacros(insertEnumMacros(result, schema, module, theTitle, suffix), schema, module, theTitle, parent, property) + return insertSchemaMacros(insertEnumMacros(result, schema, module, theTitle, suffix, enumSuffix), schema, module, theTitle, parent, property) } if (schema['$ref']) { const someJson = getPath(schema['$ref'], module) if (someJson) { - return getSchemaShape(someJson, module, { templateDir, name, parent, property, level, summary, descriptions, destination, enums }) + return getSchemaShape(someJson, module, { templateDir, name, parent, property, level, summary, descriptions, destination, enums, enumSuffix }) } throw "Unresolvable $ref: " + schema['ref'] + ", in " + module.info.title } @@ -400,7 +400,7 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name else if (!skipTitleOnce && (level > 0) && schema.title) { let enumType = (schema.type === 'string' && Array.isArray(schema.enum)) // TODO: allow the 'ref' template to actually insert the shape using getSchemaShape - const innerShape = getSchemaShape(schema, module, { skipTitleOnce: true, templateDir, name, parent, property, level, summary, descriptions, destination, enums: enumType }) + const innerShape = getSchemaShape(schema, module, { skipTitleOnce: true, templateDir, name, parent, property, level, summary, descriptions, destination, enums: enumType, enumSuffix }) const shape = getTemplate(path.join(templateDir, 'ref' + suffix)) .replace(/\$\{shape\}/g, innerShape) diff --git a/src/sdk/index.mjs b/src/sdk/index.mjs index 763b6c9e..029f457b 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, + enumSuffix: config.enumSuffix, staticModuleNames: staticModuleNames, hideExcluded: true, aggregateFiles: config.aggregateFiles, From d7bef1d28f3081b02e922f2c1494d94667e2647c Mon Sep 17 00:00:00 2001 From: HaseenaSainul Date: Tue, 10 Oct 2023 06:39:06 -0400 Subject: [PATCH 3/4] CPPSDK: enum array inside component schema also added --- src/macrofier/engine.mjs | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index 7fda8cce..cb550f87 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -375,7 +375,10 @@ const promoteSchema = (location, property, title, document, destinationPath) => } // only consider sub-objects and sub enums to be sub-schemas -const isSubSchema = (schema) => schema.type === 'object' || (schema.type === 'string' && schema.enum) // || (schema.type === 'array' && schema.items) +const isSubSchema = (schema) => schema.type === 'object' || (schema.type === 'string' && schema.enum) + +// check schema is sub enum of array +const isSubEnumOfArraySchema = (schema) => (schema.type === 'array' && schema.items.enum) const promoteAndNameSubSchemas = (obj) => { // make a copy so we don't polute our inputs @@ -402,19 +405,30 @@ const promoteAndNameSubSchemas = (obj) => { while (more) { more = false Object.entries(obj.components.schemas).forEach(([key, schema]) => { - if ((schema.type === "object") && schema.properties) { - Object.entries(schema.properties).forEach(([name, propSchema]) => { - if (isSubSchema(propSchema)) { - more = true - const descriptor = { - name: name, - schema: propSchema + let componentSchemaProperties = schema.allOf ? schema.allOf : [schema] + componentSchemaProperties.forEach((componentSchema) => { + if ((componentSchema.type === "object") && componentSchema.properties) { + Object.entries(componentSchema.properties).forEach(([name, propSchema]) => { + if (isSubSchema(propSchema)) { + more = true + const descriptor = { + name: name, + schema: propSchema + } + addContentDescriptorSubSchema(descriptor, key, obj) + componentSchema.properties[name] = descriptor.schema } - addContentDescriptorSubSchema(descriptor, key, obj) - schema.properties[name] = descriptor.schema - } - }) - } + if (isSubEnumOfArraySchema(propSchema)) { + const descriptor = { + name: name, + schema: propSchema.items + } + addContentDescriptorSubSchema(descriptor, key, obj) + componentSchema.properties[name].items = descriptor.schema + } + }) + } + }) if (!schema.title) { schema.title = capitalize(key) @@ -732,7 +746,7 @@ const convertEnumTemplate = (schema, templateName, templates) => { return template[i].replace(/\$\{key\}/g, safeName) .replace(/\$\{value\}/g, value) }).join('\n') - if (!templateName.includes(".cpp")) { + if (!templateName.includes(config.enumSuffix)) { template[i] = template[i].replace(/,*$/, ''); } } From 5bde44455971aa31388197cadccd40619d53df9a Mon Sep 17 00:00:00 2001 From: HaseenaSainul Date: Tue, 24 Oct 2023 04:18:42 -0400 Subject: [PATCH 4/4] enum handling: handling unset field + delimeter --- languages/cpp/language.config.json | 1 - languages/cpp/templates/types/enum.h | 2 +- src/macrofier/engine.mjs | 10 ++++------ src/macrofier/index.mjs | 2 -- src/macrofier/types.mjs | 26 +++++++++++++++----------- src/sdk/index.mjs | 1 - 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/languages/cpp/language.config.json b/languages/cpp/language.config.json index 541f0258..debc539d 100644 --- a/languages/cpp/language.config.json +++ b/languages/cpp/language.config.json @@ -6,7 +6,6 @@ "unwrapResultObjects": false, "createPolymorphicMethods": true, "excludeDeclarations":true, - "enumSuffix": ".cpp", "aggregateFiles": [ "/include/firebolt.h", "/src/firebolt.cpp" diff --git a/languages/cpp/templates/types/enum.h b/languages/cpp/templates/types/enum.h index 166fb231..6ec88816 100644 --- a/languages/cpp/templates/types/enum.h +++ b/languages/cpp/templates/types/enum.h @@ -1,4 +1,4 @@ /* ${title} ${description} */ enum class ${name} { - ${key}, + ${key}${delimiter},${end.delimiter} }; diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index cb550f87..c853e324 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -428,7 +428,7 @@ const promoteAndNameSubSchemas = (obj) => { } }) } - }) + }) if (!schema.title) { schema.title = capitalize(key) @@ -741,14 +741,12 @@ const convertEnumTemplate = (schema, templateName, templates) => { const template = getTemplate(templateName, templates).split('\n') for (var i = 0; i < template.length; i++) { if (template[i].indexOf('${key}') >= 0) { - template[i] = enumSchema.enum.filter(value => value).map(value => { + template[i] = enumSchema.enum.map((value, id) => { const safeName = value.split(':').pop().replace(/[\.\-]/g, '_').replace(/\+/g, '_plus').replace(/([a-z])([A-Z0-9])/g, '$1_$2').toUpperCase() return template[i].replace(/\$\{key\}/g, safeName) .replace(/\$\{value\}/g, value) + .replace(/\$\{delimiter\}(.*?)\$\{end.delimiter\}/g, id === enumSchema.enum.length - 1 ? '' : '$1') }).join('\n') - if (!templateName.includes(config.enumSuffix)) { - template[i] = template[i].replace(/,*$/, ''); - } } } return template.join('\n') @@ -881,7 +879,7 @@ function generateSchemas(json, templates, options) { else { content = content.replace(/\$\{if\.description\}(.*?)\{end\.if\.description\}/gms, '$1') } - const schemaShape = types.getSchemaShape(schema, json, { templateDir: state.typeTemplateDir, destination: state.destination, section: options.section, enumSuffix: config.enumSuffix }) + const schemaShape = types.getSchemaShape(schema, json, { templateDir: state.typeTemplateDir, destination: state.destination, section: options.section}) content = content .replace(/\$\{schema.title\}/, (schema.title || name)) diff --git a/src/macrofier/index.mjs b/src/macrofier/index.mjs index 6550a9b6..04cdd9fb 100644 --- a/src/macrofier/index.mjs +++ b/src/macrofier/index.mjs @@ -54,7 +54,6 @@ const macrofy = async ( additionalSchemaTemplates, additionalMethodTemplates, excludeDeclarations, - enumSuffix, aggregateFiles, operators, primitives, @@ -98,7 +97,6 @@ const macrofy = async ( additionalSchemaTemplates, additionalMethodTemplates, excludeDeclarations, - enumSuffix, operators }) diff --git a/src/macrofier/types.mjs b/src/macrofier/types.mjs index 275da98d..f25a9689 100644 --- a/src/macrofier/types.mjs +++ b/src/macrofier/types.mjs @@ -157,18 +157,22 @@ const insertConstMacros = (content, schema, module, name) => { return content } -const insertEnumMacros = (content, schema, module, name, suffix, enumSuffix) => { +const insertEnumMacros = (content, schema, module, name, suffix, templateDir = "types") => { const template = content.split('\n') for (var i = 0; i < template.length; i++) { if (template[i].indexOf('${key}') >= 0) { - template[i] = schema.enum.filter(value => value).map(value => { - return template[i].replace(/\$\{key\}/g, safeName(value)) - .replace(/\$\{value\}/g, value) + let values = [] + schema.enum.map(value => { + if (!value) { + value = getTemplate(path.join(templateDir, 'unset' + suffix)) + } + value ? values.push(template[i].replace(/\$\{key\}/g, safeName(value)) + .replace(/\$\{value\}/g, value)) : '' + }) + template[i] = values.map((value, id) => { + return value.replace(/\$\{delimiter\}(.*?)\$\{end.delimiter\}/g, id === values.length - 1 ? '' : '$1') }).join('\n') - if (suffix !== enumSuffix) { - template[i] = template[i].replace(/,*$/, ''); - } } } @@ -365,7 +369,7 @@ const sanitize = (schema) => { return result } -function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name = '', parent = '', property = '', level = 0, summary, descriptions = true, destination, section, enums = true, enumSuffix = '', skipTitleOnce = false } = {}) { +function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name = '', parent = '', property = '', level = 0, summary, descriptions = true, destination, section, enums = true, skipTitleOnce = false } = {}) { schema = sanitize(schema) state.destination = destination @@ -382,13 +386,13 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name if (enums && level === 0 && Array.isArray(schema.enum) && ((schema.type === "string") || (schema.type[0] === "string"))) { result = getTemplate(path.join(templateDir, 'enum' + suffix)) - return insertSchemaMacros(insertEnumMacros(result, schema, module, theTitle, suffix, enumSuffix), schema, module, theTitle, parent, property) + return insertSchemaMacros(insertEnumMacros(result, schema, module, theTitle, suffix, templateDir), schema, module, theTitle, parent, property) } if (schema['$ref']) { const someJson = getPath(schema['$ref'], module) if (someJson) { - return getSchemaShape(someJson, module, { templateDir, name, parent, property, level, summary, descriptions, destination, enums, enumSuffix }) + return getSchemaShape(someJson, module, { templateDir, name, parent, property, level, summary, descriptions, destination, enums }) } throw "Unresolvable $ref: " + schema['ref'] + ", in " + module.info.title } @@ -400,7 +404,7 @@ function getSchemaShape(schema = {}, module = {}, { templateDir = 'types', name else if (!skipTitleOnce && (level > 0) && schema.title) { let enumType = (schema.type === 'string' && Array.isArray(schema.enum)) // TODO: allow the 'ref' template to actually insert the shape using getSchemaShape - const innerShape = getSchemaShape(schema, module, { skipTitleOnce: true, templateDir, name, parent, property, level, summary, descriptions, destination, enums: enumType, enumSuffix }) + const innerShape = getSchemaShape(schema, module, { skipTitleOnce: true, templateDir, name, parent, property, level, summary, descriptions, destination, enums: enumType }) const shape = getTemplate(path.join(templateDir, 'ref' + suffix)) .replace(/\$\{shape\}/g, innerShape) diff --git a/src/sdk/index.mjs b/src/sdk/index.mjs index 029f457b..763b6c9e 100755 --- a/src/sdk/index.mjs +++ b/src/sdk/index.mjs @@ -70,7 +70,6 @@ const run = async ({ additionalSchemaTemplates: config.additionalSchemaTemplates, additionalMethodTemplates: config.additionalMethodTemplates, excludeDeclarations: config.excludeDeclarations, - enumSuffix: config.enumSuffix, staticModuleNames: staticModuleNames, hideExcluded: true, aggregateFiles: config.aggregateFiles,