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 b1d2dd89..c853e324 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) @@ -727,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.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(".cpp")) { - template[i] = template[i].replace(/,*$/, ''); - } } } return template.join('\n') @@ -867,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 }) + const schemaShape = types.getSchemaShape(schema, json, { templateDir: state.typeTemplateDir, destination: state.destination, section: options.section}) content = content .replace(/\$\{schema.title\}/, (schema.title || name)) @@ -887,7 +899,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..f25a9689 100644 --- a/src/macrofier/types.mjs +++ b/src/macrofier/types.mjs @@ -157,14 +157,21 @@ const insertConstMacros = (content, schema, module, name) => { return content } -const insertEnumMacros = (content, schema, module, name) => { +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.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') } } @@ -377,15 +384,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, 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: 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 +402,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) } })