diff --git a/languages/c/Types.mjs b/languages/c/Types.mjs index e44b4a78..0bb6cc59 100644 --- a/languages/c/Types.mjs +++ b/languages/c/Types.mjs @@ -18,365 +18,660 @@ import deepmerge from 'deepmerge' import { getPath } from '../../src/shared/json-schema.mjs' -import { getTypeName, getModuleName, description, getObjectHandleManagement, getNativeType, getPropertyAccessors, capitalize, isOptional, generateEnum, getMapAccessors, getArrayAccessors } from './src/types/NativeHelpers.mjs' -import { getObjectHandleManagementImpl, getPropertyAccessorsImpl } from './src/types/ImplHelpers.mjs' -import { getJsonContainerDefinition } from './src/types/JSONHelpers.mjs' +import { getTypeName, getModuleName, description, getObjectHandleManagement, getNativeType, getPropertyAccessors, capitalize, isOptional, generateEnum, getMapAccessors, getArrayAccessors, getArrayElementSchema } from './src/types/NativeHelpers.mjs' +import { getArrayAccessorsImpl, getMapAccessorsImpl, getObjectHandleManagementImpl, getPropertyAccessorsImpl } from './src/types/ImplHelpers.mjs' +import { getJsonContainerDefinition, getJsonDataStructName } from './src/types/JSONHelpers.mjs' -function getMethodSignature(method, module, { destination, isInterface = false }) { - const extraParam = '${method.result.type}* ${method.result.name}' - - const prefix = method.tags.find(t => t.name.split(":")[0] === "property") ? "Get" : "" +const getSdkNameSpace = () => 'FireboltSDK' +const getJsonNativeTypeForOpaqueString = () => getSdkNameSpace() + '::JSON::String' +const getEnumName = (name, prefix) => ((prefix.length > 0) ? (prefix + '_' + name) : name) - return 'uint32_t ${info.title}_' + prefix + '${method.Name}(' + extraParam + ')' +const getRefModule = (title) => { + let module = { + info: { + title: `${title}` + } + } + return module } -function getMethodSignatureParams(method, module, { destination }) { - return method.params.map(param => param.name + (!param.required ? '?' : '') + ': ' + getSchemaType(param.schema, module, { title: true, destination })).join(', ') +const hasProperties = (prop) => { + let hasProperty = false + if (prop.properties) { + hasProperty = true + } else if (prop.additionalProperties && ( prop.additionalProperties.type && (((prop.additionalProperties.type === 'object') && prop.additionalProperties.properties) || (prop.additionalProperties.type !== 'object')))) { + hasProperty = true + } + return hasProperty } -const safeName = prop => prop.match(/[.+]/) ? '"' + prop + '"' : prop - -function getSchemaType(schema, module, { name, destination, link = false, title = false, code = false, asPath = false, event = false, expandEnums = true, baseUrl = '' } = {}) { - let type = '' - let theTitle = schema.title || name || ('UnamedSchema' + (Math.floor(Math.random() * 100))) +function validJsonObjectProperties(json = {}) { - if (schema['x-method']) { - console.log(`WARNING UNHANDLED: x-method in ${theTitle}`) - //throw "x-methods not supported yet" - } - - if (schema['$ref']) { - if (schema['$ref'][0] === '#') { - //Ref points to local schema - //Get Path to ref in this module and getSchemaType - let definition = getPath(schema['$ref'], module) - let tName = definition.title || schema['$ref'].split('/').pop() - return getSchemaType(definition, module, { name: tName, destination, link, title, code, asPath, event, expandEnums, baseUrl }) + let valid = true + if (json.type === 'object' || (json.additonalProperties && typeof json.additonalProperties.type === 'object')) { + if (json.properties || json.additonalProperties) { + Object.entries(json.properties || json.additonalProperties).every(([pname, prop]) => { + if (!prop['$ref'] && (pname !== 'additionalProperties') && + ((!prop.type && !prop.const && (prop.schema && !prop.schema.type)) || (Array.isArray(prop.type) && (prop.type.find(t => t === 'null'))))) { + valid = false } + return valid + }) } - else if (schema.const) { - type = getNativeType(schema) - return type - } - else if (schema.type === 'string' && schema.enum) { - //Enum - let typeName = getTypeName(getModuleName(module), theTitle) - return typeName - } - else if (Array.isArray(schema.type)) { - let type = schema.type.find(t => t !== 'null') - console.log(`WARNING UNHANDLED: type is an array containing ${schema.type}`) - } - else if (schema.type === 'array' && schema.items) { - let res - if (Array.isArray(schema.items)) { - //TODO - const IsHomogenous = arr => new Set(arr.map(item => item.type ? item.type : typeof item)).size === 1 - if (!IsHomogenous(schema.items)) { - throw 'Heterogenous Arrays not supported yet' - } - res = getSchemaType(schema.items[0], module, { destination, link, title, code, asPath, event, expandEnums, baseUrl }) - } - else { - // grab the type for the non-array schema - res = getSchemaType(schema.items, module, { destination, link, title, code, asPath, event, expandEnums, baseUrl }) - } + } + return valid +} - if (!schema.title && !name) { - console.log(`WARNING: generated name for ${module.info.title} schema w/ no title: ${theTitle}`) - console.dir(schema) +function union(schemas, module, commonSchemas) { + + const result = {}; + for (const schema of schemas) { + for (const [key, value] of Object.entries(schema)) { + if (!result.hasOwnProperty(key)) { + // If the key does not already exist in the result schema, add it + if (value && value.anyOf) { + result[key] = union(value.anyOf, module, commonSchemas) + } else if (key === 'title' || key === 'description' || key === 'required') { + //console.warn(`Ignoring "${key}"`) + } else { + result[key] = value; } - - let n = getTypeName(getModuleName(module), theTitle) - return n + 'ArrayHandle' - } - else if (schema.allOf) { - let union = deepmerge.all([...schema.allOf.map(x => x['$ref'] ? getPath(x['$ref'], module) || x : x)]) - if (theTitle) { - union['title'] = theTitle + } else if (key === 'type') { + // If the key is 'type', merge the types of the two schemas + if(result[key] === value) { + //console.warn(`Ignoring "${key}" that is already present and same`) + } else { + console.warn(`ERROR "${key}" is not same -${JSON.stringify(result, null, 4)} ${key} ${result[key]} - ${value}`); + throw "ERROR: type is not same" } - delete union['$ref'] - return getSchemaType(union, module, { destination, link, title, code, asPath, event, expandEnums, baseUrl }) - } - else if (schema.oneOf || schema.anyOf) { - return type - //TODO - } - else if (schema.type === 'object') { - if (!schema.title && !name) { - console.log(`WARNING: generated name for ${module.info.title} schema w/ no title: ${theTitle}`) - console.dir(schema) + } else { + //If the Key is a const then merge them into an enum + if(value && value.const) { + if(result[key].enum) { + result[key].enum = Array.from(new Set([...result[key].enum, value.const])) + } + else { + result[key].enum = Array.from(new Set([result[key].const, value.const])) + delete result[key].const + } } - return getTypeName(getModuleName(module), theTitle) + 'Handle' - //TODO - } - else if (schema.type) { - type = getNativeType(schema) - return type + // If the key exists in both schemas and is not 'type', merge the values + else if (Array.isArray(result[key])) { + // If the value is an array, concatenate the arrays and remove duplicates + result[key] = Array.from(new Set([...result[key], ...value])) + } else if (result[key] && result[key].enum && value && value.enum) { + //If the value is an enum, merge the enums together and remove duplicates + result[key].enum = Array.from(new Set([...result[key].enum, ...value.enum])) + } else if (typeof result[key] === 'object' && typeof value === 'object') { + // If the value is an object, recursively merge the objects + result[key] = union([result[key], value], module, commonSchemas); + } else if (result[key] !== value) { + // If the value is a primitive and is not the same in both schemas, ignore it + //console.warn(`Ignoring conflicting value for key "${key}"`) + } + } } - - // TODO: deal with dependencies - return type + } + return result; } -//function getSchemaShape(schema = {}, module = {}, { name = '', level = 0, title, summary, descriptions = true, destination, enums = true } = {}) -// function getSchemaType() -function getSchemaShape(schema, module, { name = '', level = 0, title, summary, descriptions = true, destination = '', section = '', enums = true } = {}) { - const isHeader = destination.endsWith(".h") - const isCPP = (destination.endsWith(".cpp") && section !== 'accessors') +function getMergedSchema(module, json, name, schemas) { + let refsResolved = [...json.anyOf.map(x => x['$ref'] ? getPath(x['$ref'], module, schemas) || x : x)] + let allOfsResolved = refsResolved.map(sch => sch.allOf ? deepmerge.all([...sch.allOf.map(x => x['$ref'] ? getPath(x['$ref'], module, schemas) || x : x)]) : sch) - schema = JSON.parse(JSON.stringify(schema)) + let mergedSchema = union(allOfsResolved, module, schemas) + if (json.title) { + mergedSchema['title'] = json.title + } + else { + mergedSchema['title'] = name + } - let shape = '' + delete mergedSchema['$ref'] + return mergedSchema +} - name = schema.title || name +const deepMergeAll = (module, name, schema, schemas, options) => { + let nonRefsProperty = [...schema.allOf.map(x => x['$ref'] ? '' : x)].filter(elm => elm) + let refsProperty = [...schema.allOf.map(x => x['$ref'] ? getPath(x['$ref'], module, schemas) : '')].filter(elm => elm) + let mergedProperty = [] + let mergedParamSchema = { + type: "object", + properties: {} + } + + nonRefsProperty.forEach(p => { + if (p.properties) { + Object.entries(p.properties).every(([pname, prop]) => { + let present = false + refsProperty.forEach(refP => { + if (refP.properties) { + Object.entries(refP.properties).every(([refname, refprop]) => { + if (refname == pname) { + present = true + } + return !present + }) + } + }) + let prefixedName = (present == false) ? (name + capitalize(pname)) : pname + mergedParamSchema.properties[prefixedName] = prop + return true + }) + mergedProperty.push(mergedParamSchema) + } + }) + refsProperty.forEach(ref => mergedProperty.push(ref)) + let union = deepmerge.all(mergedProperty) + + return union +} - if (!name) { - console.log(`WARNING: schema without a name in ${module.info.title}`) - return shape - } +function getMethodSignature(method, module, { destination, isInterface = false }) { + const extraParam = '${method.result.type}* ${method.result.name}' - if (schema['$ref']) { - if (schema['$ref'][0] === '#') { - //Ref points to local schema - //Get Path to ref in this module and getSchemaType + const prefix = method.tags.find(t => t.name.split(":")[0] === "property") ? "Get" : "" - const schema = getPath(schema['$ref'], module) - const tname = name || schema['$ref'].split('/').pop() - return getSchemaShape(schema, module, { name: tname, descriptions: descriptions, level: level }) - } - } - //If the schema is a const, - else if (schema.hasOwnProperty('const') && !isCPP) { - if (level > 0) { + return 'uint32_t ${info.title}_' + prefix + '${method.Name}(' + extraParam + ')' +} - let t = description(name, schema.description) - typeName = getTypeName(getModuleName(module), name) - t += (isHeader ? getPropertyAccessors(typeName, capitalize(name), typeof schema.const, { level: level, readonly: true, optional: false }) : getPropertyAccessorsImpl(typeName, capitalize(name), getJsonType(schema, module, { level, name }), typeof schema.const, { level: level, readonly: true, optional: false })) - shape += '\n' + t - } - } - else if (schema.type === 'object') { - if (!name) { - console.log(`WARNING: unnamed schema in ${module.info.title}.`) - console.dir(schema) - shape = '' - } - else if (schema.properties) { - let tName = getTypeName(getModuleName(module), name) - let c_shape = description(name, schema.description) - let cpp_shape = '' - c_shape += '\n' + (isHeader ? getObjectHandleManagement(tName) : getObjectHandleManagementImpl(tName, getJsonType(schema, module, { name }))) - Object.entries(schema.properties).forEach(([pname, prop]) => { - c_shape += '\n' + description(pname, prop.description) - let res - if (prop.type === 'array') { - if (Array.isArray(prop.items)) { - //TODO - const IsHomogenous = arr => new Set(arr.map(item => item.type ? item.type : typeof item)).size === 1 - if (!IsHomogenous(prop.items)) { - throw 'Heterogenous Arrays not supported yet' - } - res = getSchemaType(prop.items[0], module, { name: pname, level: level, descriptions: descriptions, title: true }) - } - else { - // grab the type for the non-array schema - res = getSchemaType(prop.items, module, { name: pname, level: level, descriptions: descriptions, title: true }) - } - if (res && res.length > 0) { - let n = tName + '_' + capitalize(pname || prop.title) - let def = getArrayAccessors(n + 'Array', res) - c_shape += '\n' + def - } - else { - console.log(`a. WARNING: Type undetermined for ${name}:${pname}`) - } - } else { - res = getSchemaType(prop, module, { name: pname, descriptions: descriptions, level: level + 1, title: true }) - if (res && res.length > 0) { - c_shape += '\n' + (isHeader ? getPropertyAccessors(tName, capitalize(pname), res, { level: level, readonly: false, optional: isOptional(pname, schema) }) : getPropertyAccessorsImpl(tName, capitalize(pname), getJsonType(prop, module, { level, name }), res, { level: level, readonly: false, optional: isOptional(pname, schema) })) - } - else { - console.log(`b. WARNING: Type undetermined for ${name}:${pname}`) - } - } - }) - cpp_shape += getJsonContainerDefinition(tName, Object.entries(schema.properties).map(([name, prop]) => ({ name, type: getJsonType(prop, module) }))) +function getMethodSignatureParams(method, module, { destination }) { - if (isCPP) { - shape += '\n' + cpp_shape - } - else { - shape += '\n' + c_shape - } - } - else if (schema.propertyNames && schema.propertyNames.enum) { - //propertyNames in object not handled yet - } - else if (schema.additionalProperties && (typeof schema.additionalProperties === 'object') && !isCPP) { - //This is a map of string to type in schema - //Get the Type - let type = getSchemaType(schema.additionalProperties, module, { name: name }) - if (type && type.length > 0) { - let tName = getTypeName(getModuleName(module), name) - // type.deps.forEach(dep => structure.deps.add(dep)) - let t = description(name, schema.description) - t += '\n' + (isHeader ? getObjectHandleManagement(tName) : getObjectHandleManagementImpl(tName, getJsonType(schema, module, { name }))) - t += getMapAccessors(getTypeName(getModuleName(module), name), type, { descriptions: descriptions, level: level }) - shape += '\n' + t - } - else { - console.log(`c. WARNING: Type undetermined for ${name}`) - } - } - else if (schema.patternProperties) { - console.log(`WARNING: patternProperties not supported yet...`) - // throw "patternProperties are not supported by Firebolt" - } - } - else if (schema.anyOf) { + return method.params.map(param => param.name + (!param.required ? '?' : '') + ': ' + getSchemaType(param.schema, module, { name: param.name, title: true, destination })).join(', ') +} - } - else if (schema.oneOf) { +const safeName = prop => prop.match(/[.+]/) ? '"' + prop + '"' : prop - } - else if (schema.allOf) { - let union = deepmerge.all([...schema.allOf.map(x => x['$ref'] ? getPath(x['$ref'], module) || x : x)]) - if (name) { - union['title'] = name - } - delete union['$ref'] - return getSchemaShape(union, module, { name, level, title, summary, descriptions, destination, section, enums }) +function getSchemaType(schema, module, { name, prefix = '', destination, link = false, title = false, code = false, asPath = false, event = false, expandEnums = true, baseUrl = '' } = {}) { + let info = getSchemaTypeInfo(module, schema, name, module['x-schemas'], prefix, { title: title }) + return info.type +} - } - else if (schema.type === 'array') { - let res = getSchemaType(schema, module, { name, level: 0, descriptions: descriptions }) - // res.deps.forEach(dep => structure.deps.add(dep)) +function getSchemaTypeInfo(module = {}, json = {}, name = '', schemas = {}, prefix = '', options = {level: 0, descriptions: true, title: false}) { + + if (json.schema) { + json = json.schema + } + + let structure = {} + structure["type"] = '' + structure["json"] = [] + structure["name"] = {} + structure["namespace"] = {} + + if (json['$ref']) { + if (json['$ref'][0] === '#') { + //Ref points to local schema + //Get Path to ref in this module and getSchemaType + let definition = getPath(json['$ref'], module, schemas) + let tName = definition.title || json['$ref'].split('/').pop() + let schema = module + if (json['$ref'].includes('x-schemas')) { + schema = (getRefModule(json['$ref'].split('/')[2])) + } + + const res = getSchemaTypeInfo(schema, definition, tName, schemas, '', options) + structure.type = res.type + structure.json = res.json + structure.name = res.name + structure.namespace = res.namespace + return structure + } + } + else if (json.const) { + structure.type = getNativeType(json) + structure.json = json + return structure + } + else if (json['x-method']) { + console.log(`WARNING UNHANDLED: x-method in ${name}`) + return structure + //throw "x-methods not supported yet" + } + else if (json.type === 'string' && json.enum) { + //Enum + structure.name = name || json.title + let typeName = getTypeName(getModuleName(module), name || json.title, prefix, false, false) + let res = description(capitalize(name || json.title), json.description) + '\n' + generateEnum(json, typeName) + structure.json = json + structure.type = typeName + structure.namespace = getModuleName(module) + return structure + } + else if (Array.isArray(json.type)) { + let type = json.type.find(t => t !== 'null') + console.log(`WARNING UNHANDLED: type is an array containing ${json.type}`) + } + else if (json.type === 'array' && json.items && (validJsonObjectProperties(json) === true)) { + let res = '' + if (Array.isArray(json.items)) { + //TODO + const IsHomogenous = arr => new Set(arr.map( item => item.type ? item.type : typeof item)).size === 1 + if (!IsHomogenous(json.items)) { + throw 'Heterogenous Arrays not supported yet' + } + res = getSchemaTypeInfo(module, json.items[0], json.items[0].name || name, schemas, prefix) } else { - let res = getSchemaType(schema, module, { name, level: level, descriptions: descriptions }) - // res.deps.forEach(dep => structure.deps.add(dep)) + // grab the type for the non-array schema + res = getSchemaTypeInfo(module, json.items, json.items.name || name, schemas, prefix) + } + + let arrayName = capitalize(res.name) + capitalize(res.json.type) + let n = getTypeName(getModuleName(module), arrayName, prefix) + structure.name = res.name || name && (capitalize(name)) + structure.type = n + 'ArrayHandle' + structure.json = json + structure.namespace = getModuleName(module) + return structure + } + else if (json.allOf) { + let title = json.title ? json.title : name + let union = deepMergeAll(module, title, json, schemas, options) + union['title'] = title + + delete union['$ref'] + return getSchemaTypeInfo(module, union, '', schemas, '', options) + } + else if (json.oneOf) { + structure.type = 'char*' + structure.json.type = 'string' + return structure + } + else if (json.anyOf) { + let mergedSchema = getMergedSchema(module, json, name, schemas) + let prefixName = ((prefix.length > 0) && (!name.startsWith(prefix))) ? prefix : capitalize(name) + return getSchemaTypeInfo(module, mergedSchema, '', schemas, prefixName, options) + } + else if (json.type === 'object') { + structure.json = json + if (hasProperties(json)) { + structure.type = getTypeName(getModuleName(module), json.title || name, prefix) + 'Handle' + structure.name = (json.name ? json.name : (json.title ? json.title : name)) + structure.namespace = (json.namespace ? json.namespace : getModuleName(module)) } - // console.dir(structure.deps) - return shape -} - -// function getJsonType(schema, module, { destination, link = false, title = false, code = false, asPath = false, event = false, expandEnums = true, baseUrl = '' } = {}) { - -const getJsonDataStructName = (modName, name) => `${capitalize(modName)}::${capitalize(name)}` - -const getJsonNativeType = json => { - let type - let jsonType = json.const ? typeof json.const : json.type - - if (jsonType === 'string') { - type = 'WPEFramework::Core::JSON::String' - } - else if (jsonType === 'number' || json.type === 'integer') { //Lets keep it simple for now - type = 'WPEFramework::Core::JSON::Number' + else { + structure.type = 'char*' } - else if (jsonType === 'boolean') { - type = 'WPEFramework::Core::JSON::Boolean' + if (name) { + structure.name = capitalize(name) } - else { - throw 'Unknown JSON Native Type !!!' + + return structure + } + else if (json.type) { + structure.type = getNativeType(json) + structure.json = json + if (name || json.title) { + structure.name = capitalize(name || json.title) } - return type -} + structure.namespace = getModuleName(module) -function getJsonType(schema = {}, module = {}, { name = '', descriptions = false, level = 0 } = {}) { + return structure + } + return structure +} - let type = '' +function getSchemaShape(json, module, { name = '', prefix = '', level = 0, title, summary, descriptions = true, destination = '', section = '', enums = true } = {}) { - if (schema['$ref']) { - if (schema['$ref'][0] === '#') { - //Ref points to local schema - //Get Path to ref in this module and getSchemaType - let definition = getPath(schema['$ref'], module) - let tName = definition.title || schema['$ref'].split('/').pop() - return getJsonType(definition, module, { name: tName, descriptions: descriptions, level: level }) - } - } - else if (schema.const) { - return getJsonNativeType(schema) - } - else if (schema['x-method']) { - console.log(`WARNING: x-methods are not supported yet...`) - return type - //throw "x-methods not supported yet" - } - else if (schema.type === 'string' && schema.enum) { - //Enum - let t = getSchemaType(schema, module, { name }) - return 'WPEFramework::Core::JSON::EnumType<::' + t + '>' - } - else if (Array.isArray(schema.type)) { - let type = schema.type.find(t => t !== 'null') - console.log(`WARNING UNHANDLED: type is an array containing ${schema.type}`) + let shape = getSchemaShapeInfo(json, module, module['x-schemas'], { name, prefix, merged: false, level, title, summary, descriptions, destination, section, enums }) + return shape +} +function getSchemaShapeInfo(json, module, schemas = {}, { name = '', prefix = '', merged = false, level = 0, title, summary, descriptions = true, destination = '', section = '', enums = true } = {}) { + const isHeader = (destination.includes("JsonData_") !== true) && destination.endsWith(".h") + const isCPP = ((destination.endsWith(".cpp") || destination.includes("JsonData_")) && (section.includes('accessors') !== true)) + json = JSON.parse(JSON.stringify(json)) + + name = json.title || name + let shape = '' + + if (json['$ref']) { + if (json['$ref'][0] === '#') { + //Ref points to local schema + //Get Path to ref in this module and getSchemaType + const schema = getPath(json['$ref'], module, schemas) + const tname = schema.title || json['$ref'].split('/').pop() + if (json['$ref'].includes('x-schemas')) { + schema = (getRefModule(json['$ref'].split('/')[2])) + } + + shape = getSchemaShapeInfo(schema, module, schemas, { name, prefix, merged, level, title, summary, descriptions, destination, section, enums }) + } + } + //If the schema is a const, + else if (json.hasOwnProperty('const') && !isCPP) { + if (level > 0) { + + let t = description(capitalize(name), json.description) + typeName = getTypeName(getModuleName(module), name, prefix) + t += (isHeader ? getPropertyAccessors(typeName, capitalize(name), typeof schema.const, { level: level, readonly: true, optional: false }) : getPropertyAccessorsImpl(typeName, getJsonType(schema, module, { level, name }), typeof schema.const, { level: level, readonly: true, optional: false })) + shape += '\n' + t } - else if (schema.type === 'array' && schema.items) { - let res - if (Array.isArray(schema.items)) { + } + else if (json.type === 'object') { + if (!name) { + console.log(`WARNING: unnamed schema in ${module.info.title}.`) + console.dir(json) + shape = '' + } + else if (json.properties && (validJsonObjectProperties(json) === true)) { + let c_shape = description(capitalize(name), json.description) + let cpp_shape = '' + let tName = getTypeName(getModuleName(module), name, prefix) + c_shape += '\n' + (isHeader ? getObjectHandleManagement(tName) : getObjectHandleManagementImpl(tName, getJsonType(json, module, { name }))) + let props = [] + let containerName = ((prefix.length > 0) && (!name.startsWith(prefix))) ? (prefix + '_' + capitalize(name)) : capitalize(name) + Object.entries(json.properties).forEach(([pname, prop]) => { + let items + var desc = '\n' + description(capitalize(pname), prop.description) + if (prop.type === 'array') { + if (Array.isArray(prop.items)) { //TODO - const IsHomogenous = arr => new Set(arr.map(item => item.type ? item.type : typeof item)).size === 1 - if (!IsHomogenous(schema.items)) { - throw 'Heterogenous Arrays not supported yet' + const IsHomogenous = arr => new Set(arr.map( item => item.type ? item.type : typeof item)).size === 1 + if (!IsHomogenous(prop.items)) { + throw 'Heterogenous Arrays not supported yet' } - res = getJsonType(schema.items[0], module, { name: '' }) - } - else { + items = prop.items[0] + } + else { // grab the type for the non-array schema - res = getJsonType(schema.items, module, { name: '' }) + items = prop.items + } + let info = getSchemaTypeInfo(module, items, items.name || pname, schemas, prefix, {level : level, descriptions: descriptions, title: true}) + if (info.type && info.type.length > 0) { + let objName = tName + '_' + capitalize(prop.title || pname) + let moduleName = info.namespace + info.json.namespace = info.namespace + let moduleProperty = getJsonTypeInfo(module, json, json.title || name, schemas, prefix) + let prefixName = ((prefix.length > 0) && items['$ref']) ? '' : prefix + let subModuleProperty = getJsonTypeInfo(module, info.json, info.name, schemas, prefix) + + let t = description(capitalize(info.name), json.description) + '\n' + t += '\n' + (isHeader ? getArrayAccessors(objName, tName, info.type) : getArrayAccessorsImpl(tName, moduleProperty.type, (tName + 'Handle'), subModuleProperty.type, capitalize(pname || prop.title), info.type, info.json)) + c_shape += '\n' + t + props.push({name: `${pname}`, type: `WPEFramework::Core::JSON::ArrayType<${subModuleProperty.type}>`}) + } + else { + console.log(`a. WARNING: Type undetermined for ${name}:${pname}`) + } + } else { + if (((merged === false) || ((merged === true) && (pname.includes(name)))) && (prop.type === 'object' || prop.anyOf || prop.allOf)) { + shape += getSchemaShapeInfo(prop, module, schemas, { name : pname, prefix, merged: false, level: 1, title, summary, descriptions, destination, section, enums }) + } + let info = getSchemaTypeInfo(module, prop, pname, module['x-schemas'], prefix, {descriptions: descriptions, level: level + 1, title: true}) + if (info.type && info.type.length > 0) { + let subPropertyName = ((pname.length !== 0) ? capitalize(pname) : info.name) + let moduleProperty = getJsonTypeInfo(module, json, name, schemas, prefix) + let subProperty = getJsonTypeInfo(module, prop, pname, schemas, prefix) + c_shape += '\n' + description(capitalize(pname), info.json.description) + c_shape += '\n' + (isHeader ? getPropertyAccessors(tName, capitalize(pname), info.type, { level: 0, readonly: false, optional: isOptional(pname, json) }) : getPropertyAccessorsImpl(tName, moduleProperty.type, subProperty.type, subPropertyName, info.type, info.json, {readonly:false, optional:isOptional(pname, json)})) + let property = getJsonType(prop, module, { name : pname, prefix }) + props.push({name: `${pname}`, type: `${property}`}) + } + else { + console.log(`b. WARNING: Type undetermined for ${name}:${pname}`) + } } - - return `WPEFramework::Core::JSON::ArrayType<${res}>` + }) + + cpp_shape += getJsonContainerDefinition(json, containerName, props) + + if (isCPP) { + shape += '\n' + cpp_shape + } + else { + shape += '\n' + c_shape + } + } + else if (json.propertyNames && json.propertyNames.enum) { + //propertyNames in object not handled yet + } + else if (json.additionalProperties && (typeof json.additionalProperties === 'object') && (validJsonObjectProperties(json) === true) && !isCPP) { + let info = getSchemaTypeInfo(module, json.additionalProperties, name, module['x-schemas'], prefix) + if (!info.type || (info.type.length === 0)) { + info.type = 'char*' + info.json = json.additionalProperties + info.json.type = 'string' + } + + let tName = getTypeName(getModuleName(module), name, prefix) + let t = description(capitalize(name), json.description) + '\n' + let containerType = 'WPEFramework::Core::JSON::VariantContainer' + + let subModuleProperty = getJsonTypeInfo(module, info.json, info.name, module['x-schemas']) + if (isCPP && ((info.json.type === 'object' && info.json.properties) || info.json.type === 'array')) { + // Handle Container generation here + } + + t += '\n' + (isHeader ? getObjectHandleManagement(tName) : getObjectHandleManagementImpl(tName, containerType)) + t += (isHeader ? getMapAccessors(tName, info.type, { descriptions: descriptions, level: level }) : getMapAccessorsImpl(tName, containerType, subModuleProperty.type, info.type, info.json, { readonly: true, optional: false })) + shape += '\n' + t + } + else if (json.patternProperties) { + console.log(`WARNING: patternProperties are not supported by Firebolt(inside getModuleName(module):${name})`) + } + } + else if (json.anyOf) { + if (level > 0) { + let mergedSchema = getMergedSchema(module, json, name, schemas) + let prefixName = ((prefix.length > 0) && (!name.startsWith(prefix))) ? prefix : capitalize(name) + shape += getSchemaShapeInfo(mergedSchema, module, schemas, { name, prefix: prefixName, merged, level, title, summary, descriptions, destination, section, enums }) + } + } + else if (json.oneOf) { + //Just ignore schema shape, since this has to be treated as string + } + else if (json.allOf) { + let title = (json.title ? json.title : name) + let union = deepMergeAll(module, title, json, schemas) + union.title = title + + delete union['$ref'] + + return getSchemaShapeInfo(union, module, schemas, { name, prefix, merged: true, level, title, summary, descriptions, destination, section, enums }) + } + else if (json.type === 'array' && !isCPP) { + let j + if (Array.isArray(json.items)) { + //TODO + const IsHomogenous = arr => new Set(arr.map( item => item.type ? item.type : typeof item)).size === 1 + if (!IsHomogenous(json.items)) { + throw 'Heterogenous Arrays not supported yet' + } + j = json.items[0] } - else if (schema.allOf) { - let union = deepmerge.all([...schema.allOf.map(x => x['$ref'] ? getPath(x['$ref'], module, schemas) || x : x)]) - if (schema.title) { - union['title'] = schema.title - } - else { - union['title'] = name - } - delete union['$ref'] - return getJsonType(union, module, { name: '', level, descriptions }) - } - else if (schema.oneOf || schema.anyOf) { - return type - //TODO - } - else if (schema.type === 'object') { - if (!schema.title && !name) { - console.log(`WARNING: schema with no name`) - console.dir(schema) - return 'Unknown' - } - return getJsonDataStructName(getModuleName(module), schema.title || name) - //TODO - } - else if (schema.type) { - return getJsonNativeType(schema) - } - return type + else { + j = json.items + } + + let info = getSchemaTypeInfo(module, j, j.name || name, schemas, prefix, {level : level, descriptions: descriptions, title: true}) + + if (info.type && info.type.length > 0) { + let type = getArrayElementSchema(json, module, schemas, info.name) + let arrayName = capitalize(info.name) + capitalize(type.type) + let objName = getTypeName(info.namespace, arrayName, prefix) + let tName = objName + 'Array' + let moduleName = info.namespace + info.json.namespace = info.namespace + let moduleProperty = getJsonTypeInfo(module, json, json.title || name, schemas, prefix) + let t = '' + if (level === 0) { + t += description(capitalize(info.name), json.description) + '\n' + t += '\n' + (isHeader ? getObjectHandleManagement(tName) : getObjectHandleManagementImpl(tName, moduleProperty.type)) + } + t += '\n' + (isHeader ? getArrayAccessors(objName, tName, info.type) : getArrayAccessorsImpl(objName, moduleProperty.type, (tName + 'Handle'), getJsonNativeType(type), '', info.type, info.json)) + shape += '\n' + t + } + } + else { + shape += '\n' + getSchemaType(module, json, name, schemas, prefix, {level: level, descriptions: descriptions}) + } + + return shape } -function getTypeScriptType(jsonType) { - if (jsonType === 'integer') { - return 'number' +const getJsonNativeType = json => { + let type + let jsonType = json.const ? typeof json.const : json.type + + if (jsonType === 'string') { + type = getSdkNameSpace() + '::JSON::String' + } + else if (jsonType === 'number') { + type = 'WPEFramework::Core::JSON::Float' + } + else if (json.type === 'integer') { + type = 'WPEFramework::Core::JSON::DecSInt32' + } + else if (jsonType === 'boolean') { + type = 'WPEFramework::Core::JSON::Boolean' + } + else { + throw 'Unknown JSON Native Type !!!' + } + return type +} + +function getJsonType(schema = {}, module = {}, { name = '', prefix = '', descriptions = false, level = 0 } = {}) { + let info = getJsonTypeInfo(module, schema, name, module['x-schemas'], prefix, { descriptions: descriptions, level: level }) + return info.type +} + +function getJsonTypeInfo(module = {}, json = {}, name = '', schemas, prefix = '', {descriptions = false, level = 0} = {}) { + + if (json.schema) { + json = json.schema + } + + let structure = {} + structure["deps"] = new Set() //To avoid duplication of local ref definitions + structure["type"] = [] + + if (json['$ref']) { + if (json['$ref'][0] === '#') { + //Ref points to local schema + //Get Path to ref in this module and getSchemaType + let definition = getPath(json['$ref'], module, schemas) + let tName = definition.title || json['$ref'].split('/').pop() + + let schema = module + if (json['$ref'].includes('x-schemas')) { + schema = (getRefModule(json['$ref'].split('/')[2])) + } + + const res = getJsonTypeInfo(schema, definition, tName, schemas, '', {descriptions, level}) + structure.deps = res.deps + structure.type = res.type + return structure + } + } + else if (json.const) { + structure.type = getJsonNativeType(json) + return structure + } + else if (json['x-method']) { + return structure + //throw "x-methods not supported yet" + } + else if (json.additionalProperties && (typeof json.additionalProperties === 'object')) { + //This is a map of string to type in schema + //Get the Type + let type = getJsonTypeInfo(module, json.additionalProperties, name, schemas, prefix) + if (type.type && type.type.length > 0) { + structure.type = 'WPEFramework::Core::JSON::VariantContainer'; + return structure + } + else { + console.log(`WARNING: Type undetermined for ${name}`) + } + } + else if (json.type === 'string' && json.enum) { + //Enum + let t = 'WPEFramework::Core::JSON::EnumType<' + (json.namespace ? json.namespace : getModuleName(module)) + '_' + (getEnumName(name, prefix)) + '>' + structure.type.push(t) + return structure + } + else if (Array.isArray(json.type)) { + let type = json.type.find(t => t !== 'null') + console.log(`WARNING UNHANDLED: type is an array containing ${json.type}`) + } + else if (json.type === 'array' && json.items) { + let res + let items + if (Array.isArray(json.items)) { + //TODO + const IsHomogenous = arr => new Set(arr.map( item => item.type ? item.type : typeof item)).size === 1 + if (!IsHomogenous(json.items)) { + throw 'Heterogenous Arrays not supported yet' + } + items = json.items[0] } else { - return jsonType + items = json.items + // grab the type for the non-array schema + } + res = getJsonTypeInfo(module, items, items.name || name, schemas, prefix) + structure.deps = res.deps + structure.type.push(`WPEFramework::Core::JSON::ArrayType<${res.type}>`) + + return structure + } + else if (json.allOf) { + let title = json.title ? json.title : name + let union = deepMergeAll(module, title, json, schemas) + union['title'] = title + + delete union['$ref'] + return getJsonTypeInfo(module, union, '', schemas, '', {descriptions, level}) + } + else if (json.oneOf) { + structure.type = getJsonNativeTypeForOpaqueString() + return structure + } + else if (json.patternProperties) { + structure.type = getJsonNativeTypeForOpaqueString() + return structure + } + else if (json.anyOf) { + let mergedSchema = getMergedSchema(module, json, name, schemas) + let prefixName = ((prefix.length > 0) && (!name.startsWith(prefix))) ? prefix : capitalize(name) + structure = getJsonTypeInfo(module, mergedSchema, name, schemas, prefixName, {descriptions, level}) + } + else if (json.type === 'object') { + if (hasProperties(json) !== true) { + structure.type = getJsonNativeTypeForOpaqueString() } + else { + let schema = getSchemaTypeInfo(module, json, name, module['x-schemas'], prefix) + if (schema.namespace && schema.namespace.length > 0) { + structure.type.push(getJsonDataStructName(schema.namespace, json.title || name, prefix)) + } + } + return structure + } + else if (json.type) { + structure.type = getJsonNativeType(json) + return structure + } + return structure +} + +function getTypeScriptType(jsonType) { + if (jsonType === 'integer') { + return 'number' + } + else { + return jsonType + } } const enumReducer = (acc, val, i, arr) => { - const keyName = val.split(':').pop().replace(/[\.\-]/g, '_').replace(/\+/g, '_plus').replace(/([a-z])([A-Z0-9])/g, '$1_$2').toUpperCase() - acc = acc + ` ${keyName} = '${val}'` - if (i < arr.length - 1) { - acc = acc.concat(',\n') - } - return acc + const keyName = val.split(':').pop().replace(/[\.\-]/g, '_').replace(/\+/g, '_plus').replace(/([a-z])([A-Z0-9])/g, '$1_$2').toUpperCase() + acc = acc + ` ${keyName} = '${val}'` + if (i < arr.length - 1) { + acc = acc.concat(',\n') + } + return acc } export default { @@ -385,4 +680,4 @@ export default { getSchemaShape, getSchemaType, getJsonType -} \ No newline at end of file +} diff --git a/languages/c/src/types/ImplHelpers.mjs b/languages/c/src/types/ImplHelpers.mjs index f3b39cbf..47852c9e 100644 --- a/languages/c/src/types/ImplHelpers.mjs +++ b/languages/c/src/types/ImplHelpers.mjs @@ -1,28 +1,35 @@ const Indent = '\t' +const getSdkNameSpace = () => 'FireboltSDK' +const wpeJsonNameSpace = () => 'WPEFramework::Core::JSON' +const getFireboltStringType = () => 'FireboltTypes_StringHandle' + const getObjectHandleManagementImpl = (varName, jsonDataName) => { - let result = ` -${varName}Handle ${varName}Handle_Create(void) { + let result = `${varName}Handle ${varName}Handle_Create(void) +{ WPEFramework::Core::ProxyType<${jsonDataName}>* type = new WPEFramework::Core::ProxyType<${jsonDataName}>(); *type = WPEFramework::Core::ProxyType<${jsonDataName}>::Create(); return (static_cast<${varName}Handle>(type)); } -void ${varName}Handle_Addref(${varName}Handle handle) { +void ${varName}Handle_Addref(${varName}Handle handle) +{ ASSERT(handle != NULL); WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); ASSERT(var->IsValid()); var->AddRef(); } -void ${varName}Handle_Release(${varName}Handle handle) { +void ${varName}Handle_Release(${varName}Handle handle) +{ ASSERT(handle != NULL); WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); var->Release(); - if(var->IsValid() != true) { + if (var->IsValid() != true) { delete var; } } -bool ${varName}Handle_IsValid(${varName}Handle handle) { +bool ${varName}Handle_IsValid(${varName}Handle handle) +{ ASSERT(handle != NULL); WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); ASSERT(var->IsValid()); @@ -32,263 +39,258 @@ bool ${varName}Handle_IsValid(${varName}Handle handle) { return result } -const getPropertyAccessorsImpl = (objName, propertyName, jsonDataName, propertyType, json = {}, options = {readonly:false, optional:false}) => { - - let result - if (json.type === 'object') { - result += `${objName}_${propertyName}Handle ${objName}_Get_${propertyName}(${objName}Handle handle) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); - ASSERT(var->IsValid()); - - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* object = new WPEFramework::Core::ProxyType<${objName}::${propertyName}>(); - *object = WPEFramework::Core::ProxyType<${objName}::${propertyName}>::Create(); - *(*object) = (*var)->${propertyName}; - return (static_cast<${objName}_${propertyType}Handle>(object));` + '\n' - } else if (json.type === 'array') { - result += `${objName}_${propertyName}ArrayHandle ${objName}_Get_${propertyName}(${objName}Handle handle) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); - ASSERT(var->IsValid()); - - WPEFramework::Core::ProxyType>* object = new WPEFramework::Core::ProxyType>(); - *object = WPEFramework::Core::ProxyType>::Create(); - *(*object) = (*var)->${propertyName}.Element(); - return (static_cast<${objName}_${propertyType}ArrayHandle>(object));` + '\n' - } else if (json.enum) { - result += `${objName}_${propertyName} ${objName}_Get_${propertyName}(${objName}Handle handle) { +const getPropertyAccessorsImpl = (objName, modulePropertyType, subPropertyType, subPropertyName, accessorPropertyType, json = {}, options = {readonly:false, optional:false}) => { + let result = '' + result += `${accessorPropertyType} ${objName}_Get_${subPropertyName}(${objName}Handle handle) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - - return static_cast<${propertyType}>((*var)->${propertyName}.Value());` + '\n' - } else { - result += `${propertyType} ${objName}_Get_${propertyName}(${objName}Handle handle) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); - ASSERT(var->IsValid());` + '\n' - if (json.type === 'string') { - result += ` - return static_cast<${propertyType}>((*var)->${propertyName}.Value().c_str());` + '\n' - } else { - result += ` - return static_cast<${propertyType}>((*var)->${propertyName}.Value());` + '\n' +` + '\n' + if ((json.type === 'object') && (accessorPropertyType !== 'char*')) { + result += ` WPEFramework::Core::ProxyType<${subPropertyType}>* element = new WPEFramework::Core::ProxyType<${subPropertyType}>(); + *element = WPEFramework::Core::ProxyType<${subPropertyType}>::Create(); + *(*element) = (*var)->${subPropertyName}; + return (static_cast<${accessorPropertyType}>(element));` + '\n' + } + else { + if ((typeof json.const === 'string') || (json.type === 'string' && !json.enum) || (accessorPropertyType === 'char*')) { + result += ` return (const_cast<${accessorPropertyType}>((*var)->${subPropertyName}.Value().c_str()));` + '\n' + } + else { + result += ` return (static_cast<${accessorPropertyType}>((*var)->${subPropertyName}.Value()));` + '\n' } } - result += ` -}` + '\n' - if (!options.readonly) { - if (json.type === 'object') { - result += `${Indent.repeat(options.level)}void ${objName}_Set_${propertyName}(${objName}Handle handle, ${objName}_${propertyName}Handle ${propertyName.toLowerCase()}) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); - ASSERT(var->IsValid()); + result += `}` + '\n' - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* object = static_cast*>(${propertyName.toLowerCase()}); - (*var)->${propertyName} = *(*object);` + '\n' - } - if (json.type === 'array') { - result += `${Indent.repeat(options.level)}void ${objName}_Set_${propertyName}(${objName}Handle handle, ${objName}_${propertyName}ArrayHandle ${propertyName.toLowerCase()}) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); - ASSERT(var->IsValid()); - WPEFramework::Core::ProxyType>* object = static_cast>*>(${propertyName.toLowerCase()}).Element(); - (*var)->${propertyName} = *(*object);` + '\n' - } if (json.enum) { - result += `${Indent.repeat(options.level)}void ${objName}_Set_${propertyName}(${objName}Handle handle, ${objName}_${propertyName} ${propertyName.toLowerCase()}) { + if (!options.readonly) { + let type = (accessorPropertyType === getFireboltStringType()) ? 'char*' : accessorPropertyType + result += `void ${objName}_Set_${subPropertyName}(${objName}Handle handle, ${type} value)\n{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); +` + '\n' - (*var)->${propertyName} = static_cast<${propertyType}>(${propertyName.toLowerCase()});` + '\n' + if (json.type === 'object' && (accessorPropertyType !== 'char*')) { + result += ` WPEFramework::Core::ProxyType<${subPropertyType}>* object = static_cast*>(value); + (*var)->${subPropertyName} = *(*object);` + '\n' } else { - result += `${Indent.repeat(options.level)}void ${objName}_Set_${propertyName}(${objName}Handle handle, ${propertyType} ${propertyName.toLowerCase()}) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); - ASSERT(var->IsValid()); - - (*var)->${propertyName} = static_cast<${propertyType}>(${propertyName.toLowerCase()});` + '\n' + result += ` (*var)->${subPropertyName} = value;` + '\n' } -result += `}` + '\n' + result += `}` + '\n' } if (options.optional === true) { - result += `${Indent.repeat(options.level)}bool ${objName}_has_${propertyName}(${objName}Handle handle) { + result += `bool ${objName}_Has_${subPropertyName}(${objName}Handle handle)\n{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - return ((*var)->${propertyName}.IsSet()); + + return ((*var)->${subPropertyName}.IsSet()); }` + '\n' - result += `${Indent.repeat(options.level)}void ${objName}_clear_${propertyName}(${objName}Handle handle) { + result += `void ${objName}_Clear_${subPropertyName}(${objName}Handle handle)\n{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${jsonDataName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - ((*var)->${propertyName}.Clear()); + ((*var)->${subPropertyName}.Clear()); }` + '\n' } + return result } +const getArrayAccessorsImpl = (objName, modulePropertyType, objHandleType, subPropertyType, subPropertyName, accessorPropertyType, json = {}) => { + + let propertyName + if (subPropertyName) { + propertyName = '(*var)->' + `${subPropertyName}` + objName = objName + '_' + subPropertyName + } + else { + propertyName = '(*(*var))' + } -const getArrayAccessors = (objName, propertyName, propertyType, json = {}, options = {readonly:false, optional:false}) => { - let result = ` -uint32_t ${objName}_${propertyName}Array_Size(${objName}::${propertyName}ArrayHandle handle) { + let result = `uint32_t ${objName}Array_Size(${objHandleType} handle) { ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - return ((*var)->Length()); + return (${propertyName}.Length()); }` + '\n' - if (json.type === 'object') { -result += `${objName}_${propertyType}Handle ${objName}_${propertyName}Array_Get(${objName}_${propertyName}ArrayHandle handle, uint32_t index) { + result += `${accessorPropertyType} ${objName}Array_Get(${objHandleType} handle, uint32_t index) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType>* var = static_cast>*>(handle); - ASSERT(var->IsValid()); - WPEFramework::Core::ProxyType<${objName}::${propertyType}>* object = new WPEFramework::Core::ProxyType<${objName}::${propertyType}>(); - *object = WPEFramework::Core::ProxyType<${objName}::${propertyName}>::Create(); - *(*object) = (*var)->Get(index); - return (static_cast<${objName}_${propertyType}Handle>(object));` + '\n' - } else if (json.enum) { - result += `${objName}_${propertyType} ${objName}_${propertyName}Array_Get(${objName}_${propertyName}ArrayHandle handle, uint32_t index) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType>* var = static_cast>*>(handle); - ASSERT(var->IsValid()); - - return (static_cast<${propertyType}>((*var)->Get(index)));` + '\n' - } else { - result += `${propertyType} ${objName}_${propertyName}Array_Get(${objName}_${propertyName}ArrayHandle handle, uint32_t index) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType>* var = static_cast>*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid());` + '\n' - if (json.type === 'string') { - result += `return (static_cast<${propertyType}>((*var)->Get(index).Value().c_str()));` + '\n' - } else { - result += `return (static_cast<${propertyType}>((*var)->Get(index)));` + '\n' - } + if ((json.type === 'object') || (json.type === 'array')) { + result += `WPEFramework::Core::ProxyType<${subPropertyType}>* object = new WPEFramework::Core::ProxyType<${subPropertyType}>(); + *object = WPEFramework::Core::ProxyType<${subPropertyType}>::Create(); + *(*object) = ${propertyName}.Get(index); + return (static_cast<${accessorPropertyType}>(object));` + '\n' + } + else { + if ((typeof json.const === 'string') || (json.type === 'string' && !json.enum)) { + result += ` return (const_cast<${accessorPropertyType}>(${propertyName}.Get(index).Value().c_str()));` + '\n' + } + else { + result += ` return (static_cast<${accessorPropertyType}>(${propertyName}.Get(index)));` + '\n' + } } result += `}` + '\n' - if (json.type === 'object') { - result += `void ${objName}_${propertyName}Array_Add(${objName}_${propertyName}ArrayHandle handle, ${objName}_${propertyType}Handle value) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType>* var = static_cast>*>(handle); - ASSERT(var->IsValid()); - WPEFramework::Core::ProxyType<${objName}::${propertyType}>* object = static_cast*>(value); - - (*var)->Add(*(*object));` + '\n' - } else { - result += `void ${objName}_${propertyName}Array_Add(${objName}_${propertyName}ArrayHandle handle, ${propertyType} value) { + let type = (accessorPropertyType === getFireboltStringType()) ? 'char*' : accessorPropertyType + result += `void ${objName}Array_Add(${objHandleType} handle, ${type} value) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType>* var = static_cast>*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid());` + '\n' - if (json.type === 'string') { - result += `WPEFramework::Core::JSON::String element(value);` + '\n' - } else if (json.type === 'number') { - result += `WPEFramework::Core::JSON::Number element(value);` + '\n' - } else if (json.enum) { - result += `WPEFramework::Core::JSON::EnumType<${propertyType}> element(value);` + '\n' - } - result += `(*var)->Add(element);` + '\n' + + if ((json.type === 'object') || (json.type === 'array')) { + result += ` ${subPropertyType}& element = *(*(static_cast*>(value)));` + '\n' } - result += `}` + '\n' + else { + result += ` ${subPropertyType} element(value);` + '\n' + } + result += ` + ${propertyName}.Add(element); +}` + '\n' - result += `void ${objName}_${propertyName}Array_Clear(${objName}_${propertyName}ArrayHandle handle) { + result += `void ${objName}Array_Clear(${objHandleType} handle) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType>* var = static_cast>*>(handle); + WPEFramework::Core::ProxyType<${modulePropertyType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - (*var)->Clear(); + + ${propertyName}.Clear(); }` + '\n' return result } -const getMapAccessors = (objName, propertyName, propertyType, json = {}, options = {readonly:false, optional:false}) => { - let result = `uint32_t ${objName}_${propertyName}_KeysCount(${objName}_${propertyName}Handle handle) { +const getMapAccessorsImpl = (objName, containerType, subPropertyType, accessorPropertyType, json = {}, options = {readonly:false, optional:false}) => { + let result = `uint32_t ${objName}_KeysCount(${objName}Handle handle) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${containerType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - return (*var)->Size()); - - }` + '\n' - result += `void ${objName}_${propertyName}_AddKey(${objName}_${propertyName}Handle handle, char* key, ${propertyType} value) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* var = static_cast*>(handle); - ASSERT(var->IsValid());` + '\n' - - if (json.type === 'object') { - result += ` - (*var)->Add(key, value);` + '\n' - } else if (json.type === 'boolean') { - result += ` - WPEFramework::Core::JSON::Boolean element(value);` - } else if (json.type === 'string') { - result += ` - WPEFramework::Core::JSON::String element(value);` - } else if (json.type === 'number') { - result += ` - WPEFramework::Core::JSON::Number element(value);` - } else if (json.type === 'array') { - result += ` - WPEFramework::Core::JSON::ArrayType element(value);` - } else if (json.enum) { - result += ` - WPEFramework::Core::JSON::EnumType element(value); - (*var)->Add(key, element);` + '\n' + ${containerType}::Iterator elements = (*var)->Variants(); + uint32_t count = 0; + while (elements.Next()) { + count++; } - result += ` - }` + '\n' - result += `void ${objName}_${propertyName}_RemoveKey(${objName}_${propertyName}Handle handle, char* key) { + return (count); +}` + '\n' + result += `void ${objName}_AddKey(${objName}Handle handle, char* key, ${accessorPropertyType} value) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${containerType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - - (*var)->Remove(key); - }` + '\n' +` + '\n' + let elementContainer = subPropertyType + if (containerType.includes('VariantContainer')) { + elementContainer = 'WPEFramework::Core::JSON::Variant' + } + if ((json.type === 'object') || (json.type === 'array' && json.items)) { + if (containerType.includes('VariantContainer')) { + result += ` ${subPropertyType}& container = *(*(static_cast*>(value)));` + '\n' + result += ` string containerStr;` + '\n' + result += ` element.ToString(containerStr);` + '\n' + result += ` WPEFramework::Core::JSON::VariantContainer containerVariant(containerStr);` + '\n' + result += ` WPEFramework::Core::JSON::Variant element = containerVariant;` + '\n' + } + else { + result += ` ${subPropertyType}& element = *(*(static_cast*>(value)));` + '\n' + } + } else { + result += ` ${elementContainer} element(value);` + '\n' + } + result += ` (*var)->Set(const_cast(key), element); +}` + '\n' - if (json.type === 'object') { - result += `${objName}_${propertyType}Handle ${objName}_${propertyName}_FindKey(${objName}_${propertyName}Handle handle, char* key) { + result += `void ${objName}_RemoveKey(${objName}Handle handle, char* key) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${containerType}>* var = static_cast*>(handle); ASSERT(var->IsValid()); - WPEFramework::Core::ProxyType<${objName}::${propertyType}>* object = new WPEFramework::Core::ProxyType<${objName}::${propertyType}>(); - *object = WPEFramework::Core::ProxyType<${objName}::${propertyName}>::Create(); - *(*object) = (*var)->Find(key); - return (static_cast<${objName}_${propertyType}Handle>(object));` + '\n' - } else if (json.type === 'array') { - result += `${objName}_${propertyType}ArrayHandle ${objName}_${propertyName}_FindKey(${objName}_${propertyName}Handle handle, char* key) { - ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* var = static_cast*>(handle); - ASSERT(var->IsValid()); - WPEFramework::Core::ProxyType>* object = new WPEFramework::Core::ProxyType>(); - *object = WPEFramework::Core::ProxyType>::Create(); - *(*object) = (*var)->Find(key); - return (static_cast<${objName}_${propertyType}ArrayHandle>(object));` + '\n' + (*var)->Remove(key); +}` + '\n' - } else { - result += `${propertyType} ${objName}_${propertyName}_FindKey(${objName}_${propertyName}Handle handle, char* key) { + result += `${accessorPropertyType} ${objName}_FindKey(${objName}Handle handle, char* key) +{ ASSERT(handle != NULL); - WPEFramework::Core::ProxyType<${objName}::${propertyName}>* var = static_cast*>(handle); + WPEFramework::Core::ProxyType<${containerType}>* var = static_cast*>(handle); ASSERT(var->IsValid());` + '\n' - - if (json.type === 'string') { + if ((json.type === 'object') || (json.type === 'array') || + ((json.type === 'string' || (typeof json.const === 'string')) && !json.enum)) { + result += ` ${accessorPropertyType} status = nullptr;` + '\n' + } + else if (json.type === 'boolean') { + result += ` ${accessorPropertyType} status = false;` + '\n' + } + else { + result += ` ${accessorPropertyType} status = 0;` + '\n' + } + + result += ` + if ((*var)->HasLabel(key) == true) {` + if (json.type === 'object') { + result += ` + string objectStr; + (*var)->Get(key).Object().ToString(objectStr); + ${subPropertyType} objectMap; + objectMap.FromString(objectStr); + + WPEFramework::Core::ProxyType<${subPropertyType}>* element = new WPEFramework::Core::ProxyType<${subPropertyType}>(); + *element = WPEFramework::Core::ProxyType<${subPropertyType}>::Create(); + *(*element) = objectMap; + + status = (static_cast<${accessorPropertyType}>(element));` + '\n' + } + else if (json.type === 'array' && json.items) { + result += ` + WPEFramework::Core::ProxyType<${subPropertyType}>* element = new WPEFramework::Core::ProxyType<${subPropertyType}>(); + *element = WPEFramework::Core::ProxyType<${subPropertyType}>::Create(); + *(*element) = (*var)->Get(key).Array(); + status = (static_cast<${accessorPropertyType}>(element));` + '\n' + } + else { + if (json.type === 'string' || (typeof json.const === 'string')) { + if (json.enum) { + result += ` + status = (const_cast<${accessorPropertyType}>((*var)->Get(key).));` + '\n' + } + else { + result += ` + status = (const_cast<${accessorPropertyType}>((*var)->Get(key).String().c_str()));` + '\n' + } + } + else if (json.type === 'boolean') { + result += ` + status = (static_cast<${accessorPropertyType}>((*var)->Get(key).Boolean()));` + '\n' + } + else if (json.type === 'number') { result += ` - return (static_cast<${propertyType}>((*var)->(Find(key).Value().c_str())));` + '\n' - } else { + status = (static_cast<${accessorPropertyType}>((*var)->Get(key).Float()));` + '\n' + } + else if (json.type === 'integer') { result += ` - return (static_cast<${propertyType}>((*var)->(Find(key).Value())));` + '\n' + status = (static_cast<${accessorPropertyType}>((*var)->Get(key).Number()));` + '\n' } } - result += ` -}` + '\n' + result += ` } + return status; +}` return result } export { + getArrayAccessorsImpl, + getMapAccessorsImpl, getObjectHandleManagementImpl, getPropertyAccessorsImpl } diff --git a/languages/c/src/types/JSONHelpers.mjs b/languages/c/src/types/JSONHelpers.mjs index 97a9385a..3437c98c 100644 --- a/languages/c/src/types/JSONHelpers.mjs +++ b/languages/c/src/types/JSONHelpers.mjs @@ -1,31 +1,54 @@ const capitalize = str => str[0].toUpperCase() + str.substr(1) +const getSdkNameSpace = () => 'FireboltSDK' +const getJsonDataPrefix = () => 'JsonData_' +const wpeJsonNameSpace = () => 'WPEFramework::Core::JSON' -function getJsonContainerDefinition (name, props) { - name = capitalize(name) - let c = ` class ${name}: public Core::JSON::Container { - public: - ${name}(const ${name}&) = delete; - ${name}& operator=(const ${name}&) = delete; - ~${name}() override = default; - - public: - ${name}() - : Core::JSON::Container() - {` +const getJsonDataStructName = (modName, name, prefix = '') => { + let result =((prefix.length > 0) && (!name.startsWith(prefix))) ? `${capitalize(modName)}::${getJsonDataPrefix()}${capitalize(prefix)}_${capitalize(name)}` : `${capitalize(modName)}::${getJsonDataPrefix()}${capitalize(name)}` + + return ((result.includes(wpeJsonNameSpace()) === true) ? result : `${getSdkNameSpace()}::${result}`) +} + +function getJsonContainerDefinition (schema, name, props) { + let c = schema.description ? (' /*\n * ${info.title} - ' + `${schema.description}\n */\n`) : '' + name = getJsonDataPrefix() + capitalize(name) + c += ` class ${name}: public WPEFramework::Core::JSON::Container { + public: + ~${name}() override = default; - props.forEach(prop => { - c += `\n Add(_T("${prop.name}"), &${capitalize(prop.name)});` - }) + public: + ${name}() + : WPEFramework::Core::JSON::Container() + {` - c += `\n }\n\n public:` + props.forEach(prop => { + c += `\n Add(_T("${prop.name}"), &${capitalize(prop.name)});` + }) + c += `\n }\n` + c += `\n ${name}(const ${name}& copy) + {` + props.forEach(prop => { + c += `\n Add(_T("${prop.name}"), &${capitalize(prop.name)});` + c += `\n ${capitalize(prop.name)} = copy.${capitalize(prop.name)};` + }) + c += ` + }\n + ${name}& operator=(const ${name}& rhs) + {` + props.forEach(prop => { + c += `\n ${capitalize(prop.name)} = rhs.${capitalize(prop.name)};` + }) + c += `\n return (*this); + }\n + public:` - props.forEach(prop => { - c += `\n ${prop.type} ${capitalize(prop.name)};` - }) + props.forEach(prop => { + c += `\n ${prop.type} ${capitalize(prop.name)};` + }) - c += '\n };' - return c - } + c += '\n };' + return c +} export { getJsonContainerDefinition diff --git a/languages/c/src/types/NativeHelpers.mjs b/languages/c/src/types/NativeHelpers.mjs index 79242d1f..eac20c16 100644 --- a/languages/c/src/types/NativeHelpers.mjs +++ b/languages/c/src/types/NativeHelpers.mjs @@ -29,6 +29,7 @@ const { isObject, isArray, propEq, pathSatisfies, hasProp, propSatisfies } = pre const getModuleName = json => getPathOr(null, ['info', 'title'], json) || json.title || 'missing' +const getFireboltStringType = () => 'FireboltTypes_StringHandle' const getHeaderText = () => { return `/* @@ -83,35 +84,53 @@ const SdkTypesPrefix = 'Firebolt' const Indent = ' ' -const getNativeType = json => { - let type - - if (json.const) { - if (typeof json.const === 'string') { - type = 'char*' - } - else if (typeof json.const === 'number') { - type = 'uint32_t' - if (json.const < 0) - type = 'int32_t' - } else if (typeof json.const === 'boolean'){ - type = 'bool' - } +const getArrayElementSchema = (json, module, schemas = {}, name) => { + let result = '' + if (json.type === 'array' && json.items) { + if (Array.isArray(json.items)) { + result = json.items[0] } - else if (json.type === 'string') { - type = 'char*' + else { + // grab the type for the non-array schema + result = json.items } - else if (json.type === 'number' || json.type === 'integer') { //Lets keep it simple for now - type = 'uint32_t' - if ((json.minimum && json.minimum < 0) - || (json.exclusiveMinimum && json.exclusiveMinimum < 0)) { - type = 'int32_t' - } + if (result['$ref']) { + result = getPath(result['$ref'], module, schemas) } - else if (json.type === 'boolean') { - type = 'bool' + } + else if (json.type == 'object') { + if (json.properties) { + Object.entries(json.properties).every(([pname, prop]) => { + if (prop.type === 'array') { + result = getArrayElementSchema(prop, module, schemas) + if (name === capitalize(pname)) { + return false + } + } + return true + }) } - return type + } + + return result +} + +const getNativeType = json => { + let type = '' + let jsonType = json.const ? typeof json.const : json.type + if (jsonType === 'string') { + type = 'char*' + } + else if (jsonType === 'number') { + type = 'float' + } + else if (jsonType === 'integer') { + type = 'int32_t' + } + else if (jsonType === 'boolean') { + type = 'bool' + } + return type } const getObjectHandleManagement = varName => { @@ -126,46 +145,51 @@ bool ${varName}Handle_IsValid(${varName}Handle handle); } const getPropertyAccessors = (objName, propertyName, propertyType, options = {level:0, readonly:false, optional:false}) => { - let result = `${Indent.repeat(options.level)}${propertyType} ${objName}_Get_${propertyName}(${objName}Handle handle);` + '\n' if (!options.readonly) { - result += `${Indent.repeat(options.level)}void ${objName}_Set_${propertyName}(${objName}Handle handle, ${propertyType} ${propertyName.toLowerCase()});` + '\n' + let type = (propertyType === getFireboltStringType()) ? 'char*' : propertyType + result += `${Indent.repeat(options.level)}void ${objName}_Set_${propertyName}(${objName}Handle handle, ${type} ${propertyName.toLowerCase()});` + '\n' } if (options.optional === true) { - result += `${Indent.repeat(options.level)}bool ${objName}_has_${propertyName}(${objName}Handle handle);` + '\n' - result += `${Indent.repeat(options.level)}void ${objName}_clear_${propertyName}(${objName}Handle handle);` + '\n' + result += `${Indent.repeat(options.level)}bool ${objName}_Has_${propertyName}(${objName}Handle handle);` + '\n' + result += `${Indent.repeat(options.level)}void ${objName}_Clear_${propertyName}(${objName}Handle handle);` + '\n' } return result } -const getMapAccessors = (typeName, nativeType, level=0) => { +const getMapAccessors = (typeName, accessorPropertyType, level = 0) => { let res res = `${Indent.repeat(level)}uint32_t ${typeName}_KeysCount(${typeName}Handle handle);` + '\n' - res += `${Indent.repeat(level)}void ${typeName}_AddKey(${typeName}Handle handle, char* key, ${nativeType} value);` + '\n' + res += `${Indent.repeat(level)}void ${typeName}_AddKey(${typeName}Handle handle, char* key, ${accessorPropertyType} value);` + '\n' res += `${Indent.repeat(level)}void ${typeName}_RemoveKey(${typeName}Handle handle, char* key);` + '\n' - res += `${Indent.repeat(level)}${nativeType} ${typeName}_FindKey(${typeName}Handle handle, char* key);` + '\n' + res += `${Indent.repeat(level)}${accessorPropertyType} ${typeName}_FindKey(${typeName}Handle handle, char* key);` + '\n' return res } -const getTypeName = (moduleName, varName, upperCase = false) => { - let mName = upperCase ? moduleName.toUpperCase() : capitalize(moduleName) - let vName = upperCase ? varName.toUpperCase() : capitalize(varName) +const getTypeName = (moduleName, varName, prefix = '', upperCase = false, capitalCase = true) => { - return `${mName}_${vName}` + let mName = upperCase ? moduleName.toUpperCase() : capitalize(moduleName) + let vName = upperCase ? varName.toUpperCase() : capitalCase ? capitalize(varName) : varName + if (prefix.length > 0) { + prefix = (!varName.startsWith(prefix)) ? (upperCase ? prefix.toUpperCase() : capitalize(prefix)) : '' + } + prefix = (prefix.length > 0) ?(upperCase ? prefix.toUpperCase() : capitalize(prefix)) : prefix + let name = (prefix.length > 0) ? `${mName}_${prefix}_${vName}` : `${mName}_${vName}` + return name } -const getArrayAccessors = (arrayName, valueType) => { +const getArrayAccessors = (arrayName, propertyType, valueType) => { - let res = `uint32_t ${arrayName}_Size(${arrayName}Handle handle);` + '\n' - res += `${valueType} ${arrayName}_Get(${arrayName}Handle handle, uint32_t index);` + '\n' - res += `void ${arrayName}_Add(${arrayName}Handle handle, ${valueType} value);` + '\n' - res += `void ${arrayName}_Clear(${arrayName}Handle handle);` + '\n' + let res = `uint32_t ${arrayName}Array_Size(${propertyType}Handle handle);` + '\n' + res += `${valueType} ${arrayName}Array_Get(${propertyType}Handle handle, uint32_t index);` + '\n' + res += `void ${arrayName}Array_Add(${propertyType}Handle handle, ${valueType} value);` + '\n' + res += `void ${arrayName}Array_Clear(${propertyType}Handle handle);` + '\n' return res } @@ -201,25 +225,25 @@ const getIncludeDefinitions = (json = {}, jsonData = false) => { .concat([`#include "Firebolt/Types.h"`]) } - function getPropertyGetterSignature(method, module, paramType) { - let m = `${capitalize(getModuleName(module))}_Get${capitalize(method.name)}` - return `${description(method.name, method.summary)}\nuint32 ${m}( ${paramType === 'char*' ? 'FireboltTypes_StringHandle' : paramType}* ${method.result.name || method.name} )` - } +function getPropertyGetterSignature(method, module, paramType) { + let m = `${capitalize(getModuleName(module))}_Get${capitalize(method.name)}` + return `${description(method.name, method.summary)}\nuint32 ${m}( ${paramType === 'char*' ? 'FireboltTypes_StringHandle' : paramType}* ${method.result.name || method.name} )` +} - function getPropertySetterSignature(method, module, paramType) { - let m = `${capitalize(getModuleName(module))}_Set${capitalize(method.name)}` - return `${description(method.name, method.summary)}\nuint32 ${m}( ${paramType} ${method.result.name || method.name} )` - } +function getPropertySetterSignature(method, module, paramType) { + let m = `${capitalize(getModuleName(module))}_Set${capitalize(method.name)}` + return `${description(method.name, method.summary)}\nuint32 ${m}( ${paramType} ${method.result.name || method.name} )` +} - function getPropertyEventCallbackSignature(method, module, paramType) { - return `typedef void (*On${capitalize(method.name)}Changed)(${paramType === 'char*' ? 'FireboltTypes_StringHandle' : paramType})` - } +function getPropertyEventCallbackSignature(method, module, paramType) { + return `typedef void (*On${capitalize(method.name)}Changed)(${paramType === 'char*' ? 'FireboltTypes_StringHandle' : paramType})` +} - function getPropertyEventSignature(method, module) { - return `${description(method.name, 'Listen to updates')}\n` + `uint32_t ${capitalize(getModuleName(module))}_Listen${capitalize(method.name)}Update(On${capitalize(method.name)}Changed notification, uint16_t* listenerId)` - } +function getPropertyEventSignature(method, module) { + return `${description(method.name, 'Listen to updates')}\n` + `uint32_t ${capitalize(getModuleName(module))}_Listen${capitalize(method.name)}Update(On${capitalize(method.name)}Changed notification, uint16_t* listenerId)` +} - export { +export { getHeaderText, getIncludeGuardOpen, getStyleGuardOpen, @@ -240,5 +264,6 @@ const getIncludeDefinitions = (json = {}, jsonData = false) => { getObjectHandleManagement, getPropertyAccessors, isOptional, - generateEnum - } + generateEnum, + getArrayElementSchema +} diff --git a/languages/c/templates/methods/property.c b/languages/c/templates/methods/property.c index 8f301bea..1c70ba29 100644 --- a/languages/c/templates/methods/property.c +++ b/languages/c/templates/methods/property.c @@ -1,12 +1,12 @@ /* ${method.name} - ${method.description} */ uint32_t ${info.title}_Get${method.Name}(${method.params}${if.params}, ${end.if.params}${method.result.type}* ${method.result.name}) { - const string method = _T("${info.title}.${method.name}"); - FireboltSDK::${info.title}::${method.result.type} jsonResult; + const string method = _T("${info.title}.${method.name}"); + FireboltSDK::${info.title}::${method.result.type} jsonResult; - uint32_t status = FireboltSDK::Properties::Get(method, jsonResult); - if (status == FireboltSDKErrorNone) { - WPEFramework::Core::ProxyType* resultPtr = new WPEFramework::Core::ProxyType(); - *${method.result.name} = static_cast<${info.title}_${method.result.type}Handle>(resultPtr); - } - return status; + uint32_t status = FireboltSDK::Properties::Get(method, jsonResult); + if (status == FireboltSDKErrorNone) { + WPEFramework::Core::ProxyType* resultPtr = new WPEFramework::Core::ProxyType(); + *${method.result.name} = static_cast<${info.title}_${method.result.type}Handle>(resultPtr); + } + return status; } diff --git a/languages/c/templates/modules/include/Module.h b/languages/c/templates/modules/include/Module.h index ee034605..a202f643 100644 --- a/languages/c/templates/modules/include/Module.h +++ b/languages/c/templates/modules/include/Module.h @@ -30,10 +30,6 @@ extern "C" { /* ${ENUMS} */ -// Types - -/* ${TYPES} */ - /* ${ACCESSORS} */ /* ${DECLARATIONS} */ diff --git a/languages/c/templates/modules/src/Module.cpp b/languages/c/templates/modules/src/Module.cpp index 346d07cd..c412abf2 100644 --- a/languages/c/templates/modules/src/Module.cpp +++ b/languages/c/templates/modules/src/Module.cpp @@ -25,7 +25,6 @@ namespace FireboltSDK { namespace ${info.title} { // Types - /* ${TYPES} */ } } diff --git a/languages/c/templates/schemas/default.c b/languages/c/templates/schemas/default.c index a2058da5..9a52cff7 100644 --- a/languages/c/templates/schemas/default.c +++ b/languages/c/templates/schemas/default.c @@ -1,4 +1 @@ -/* - * ${schema.description} - */ ${schema.shape} diff --git a/languages/c/templates/schemas/src/JsonData_Module.h b/languages/c/templates/schemas/src/JsonData_Module.h index 9ba90428..7fa2b6f4 100644 --- a/languages/c/templates/schemas/src/JsonData_Module.h +++ b/languages/c/templates/schemas/src/JsonData_Module.h @@ -20,6 +20,6 @@ namespace FireboltSDK { namespace ${info.title} { // Types - /* ${SCHEMAS}*/ + /* ${SCHEMAS} */ } } diff --git a/languages/c/templates/sections/accessors.c b/languages/c/templates/sections/accessors.c index 0586b2a5..1c790810 100644 --- a/languages/c/templates/sections/accessors.c +++ b/languages/c/templates/sections/accessors.c @@ -1,3 +1,2 @@ // Accessors - ${schema.list} diff --git a/languages/c/templates/sections/methods.c b/languages/c/templates/sections/methods.c index 3f382a63..3ab606c0 100644 --- a/languages/c/templates/sections/methods.c +++ b/languages/c/templates/sections/methods.c @@ -1,3 +1,4 @@ - // Methods +// Methods + ${method.list} diff --git a/languages/c/templates/sections/methods_accessors.c b/languages/c/templates/sections/methods_accessors.c new file mode 100644 index 00000000..9295133c --- /dev/null +++ b/languages/c/templates/sections/methods_accessors.c @@ -0,0 +1 @@ +${schema.list} diff --git a/languages/c/templates/sections/methods_types.c b/languages/c/templates/sections/methods_types.c new file mode 100644 index 00000000..9295133c --- /dev/null +++ b/languages/c/templates/sections/methods_types.c @@ -0,0 +1 @@ +${schema.list} diff --git a/src/macrofier/engine.mjs b/src/macrofier/engine.mjs index 66df3a47..2883fce1 100644 --- a/src/macrofier/engine.mjs +++ b/src/macrofier/engine.mjs @@ -65,6 +65,7 @@ const state = { } const capitalize = str => str[0].toUpperCase() + str.substr(1) +const hasMethodsSchema = (json, options) => json.methods && json.methods.length const setTyper = (t) => { types = t @@ -101,15 +102,11 @@ const getTemplateForExampleResult = (method, templates) => { return template || JSON.stringify(method.examples[0].result.value, null, '\t') } -const getLinkForSchema = (schema, json) => { +const getLinkForSchema = (schema, json, { name = '' } = {}) => { const dirs = config.createModuleDirectories const copySchemasIntoModules = config.copySchemasIntoModules - if (schema.schema) { - schema = schema.schema - } - - const type = types.getSchemaType(schema, json, { destination: state.destination, section: state.section }) + const type = types.getSchemaType(schema, json, { name: name, destination: state.destination, section: state.section }) // local - insert a bogus link, that we'll udpate later based on final table-of-contents if (json.components.schemas[type]) { @@ -336,16 +333,22 @@ const generateMacros = (obj, templates, languages, options = {}) => { const declarations = declarationsArray.length ? getTemplate('/sections/declarations', templates).replace(/\$\{declaration\.list\}/g, declarationsArray.map(m => m.declaration).join('\n')) : '' const methods = methodsArray.length ? getTemplate('/sections/methods', templates).replace(/\$\{method.list\}/g, methodsArray.map(m => m.body).join('\n')) : '' const methodList = methodsArray.filter(m => m.body).map(m => m.name) + const methodTypesArray = generateSchemas(obj, templates, { baseUrl: '', section: 'methods_schemas' }).filter(s => (options.copySchemasIntoModules || !s.uri)) + const methodTypes = methodTypesArray.length ? getTemplate('/sections/methods_types', templates).replace(/\$\{schema.list\}/g, methodTypesArray.map(s => s.body).filter(body => body).join('\n')) : '' + const methodAccessorsArray = generateSchemas(obj, templates, { baseUrl: '', section: 'methods_accessors' }).filter(s => (options.copySchemasIntoModules || !s.uri)) + const methodAccessors = methodAccessorsArray.length ? getTemplate('/sections/methods_accessors', templates).replace(/\$\{schema.list\}/g, methodAccessorsArray.map(s => s.body).filter(body => body).join('\n')) : '' + const providerInterfaces = generateProviderInterfaces(obj, templates) const events = eventsArray.length ? getTemplate('/sections/events', templates).replace(/\$\{event.list\}/g, eventsArray.map(m => m.body).join('\n')) : '' const eventList = eventsArray.map(m => makeEventName(m)) const defaults = generateDefaults(obj, templates) const schemasArray = generateSchemas(obj, templates, { baseUrl: '', section: 'schemas' }).filter(s => (options.copySchemasIntoModules || !s.uri)) const accessorsArray = generateSchemas(obj, templates, { baseUrl: '', section: 'accessors' }).filter(s => (options.copySchemasIntoModules || !s.uri)) - const schemas = schemasArray.length ? getTemplate('/sections/schemas', templates).replace(/\$\{schema.list\}/g, schemasArray.map(s => s.body).join('\n')) : '' + const schemas = schemasArray.length ? getTemplate('/sections/schemas', templates).replace(/\$\{schema.list\}/g, schemasArray.map(s => s.body).filter(body => body).join('\n')) : '' const typesArray = schemasArray.filter(x => !x.enum) - const types = typesArray.length ? getTemplate('/sections/types', templates).replace(/\$\{schema.list\}/g, typesArray.map(s => s.body).join('\n')) : '' - const accessors = accessorsArray.length ? getTemplate('/sections/accessors', templates).replace(/\$\{schema.list\}/g, accessorsArray.map(s => s.body).join('\n')) : '' + const types = (typesArray.length ? getTemplate('/sections/types', templates).replace(/\$\{schema.list\}/g, typesArray.map(s => s.body).filter(body => body).join('\n')) : '') + methodTypes + + const accessors = (accessorsArray.length ? getTemplate('/sections/accessors', templates).replace(/\$\{schema.list\}/g, accessorsArray.map(s => s.body).filter(body => body).join('\n')) : '') + methodAccessors const module = getTemplate('/codeblocks/module', templates) const macros = { @@ -622,9 +625,9 @@ const isEnum = x => x.type && x.type === 'string' && Array.isArray(x.enum) && x. function generateSchemas(json, templates, options) { let results = [] - const schemas = json.definitions || (json.components && json.components.schemas) || {} + const schemas = (options.section.includes('methods') ? (hasMethodsSchema(json) ? json.methods : '') : (json.definitions || (json.components && json.components.schemas) || {})) - const generate = (name, schema, uri) => { + const generate = (name, schema, uri, { prefix = '' } = {}) => { // these are internal schemas used by the firebolt-openrpc tooling, and not meant to be used in code/doc generation if (['ListenResponse', 'ProviderRequest', 'ProviderResponse', 'FederatedResponse', 'FederatedRequest'].includes(name)) { return @@ -645,7 +648,7 @@ function generateSchemas(json, templates, options) { else { content = content.replace(/\$\{if\.description\}(.*?)\{end\.if\.description\}/gms, '$1') } - const schemaShape = types.getSchemaShape(schema, json, { name, destination: state.destination, section: options.section }) + const schemaShape = types.getSchemaShape(schema, json, { name, prefix, destination: state.destination, section: options.section }) content = content .replace(/\$\{schema.title\}/, (schema.title || name)) @@ -663,6 +666,9 @@ function generateSchemas(json, templates, options) { else { content = content.replace(/.*\$\{schema.seeAlso\}/, '') } + content = content.trim().length ? content.trimEnd() : content.trim() + + const isEnum = x => x.type === 'string' && Array.isArray(x.enum) && x.title const result = uri ? { uri: uri, @@ -685,6 +691,18 @@ function generateSchemas(json, templates, options) { if (isSchema(schema)) { list.push([name, schema]) } + else if (schema.tags) { + if (!isDeprecatedMethod(schema)) { + schema.params.forEach(param => { + if (param.schema && (param.schema.type === 'object')) { + list.push([param.name, param.schema, '', { prefix : schema.name}]) + } + }) + if (schema.result.schema && (schema.result.schema.type === 'object')) { + list.push([schema.result.name, schema.result.schema, '', { prefix : schema.name}]) + } + } + } }) list.sort((a, b) => { @@ -716,7 +734,7 @@ function getRelatedSchemaLinks(schema = {}, json = {}, templates = {}, options = .map(path => path.substring(2).split('/')) .map(path => getPathOr(null, path, json)) .filter(schema => schema.title) - .map(schema => '[' + types.getSchemaType(schema, json, { destination: state.destination, section: state.section }) + '](' + getLinkForSchema(schema, json, true) + ')') // need full module here, not just the schema + .map(schema => '[' + types.getSchemaType(schema, json, { name: schema.title, destination: state.destination, section: state.section }) + '](' + getLinkForSchema(schema, json, { name: schema.title }) + ')') // need full module here, not just the schema .filter(link => link) .join('\n') @@ -1060,10 +1078,10 @@ function insertMethodMacros(template, methodObj, json, templates, examples={}) { .replace(/\$\{method\.capabilities\}/g, capabilities) .replace(/\$\{method\.result\.name\}/g, result.name) .replace(/\$\{method\.result\.summary\}/g, result.summary) - .replace(/\$\{method\.result\.link\}/g, getLinkForSchema(result, json)) //, baseUrl: options.baseUrl - .replace(/\$\{method\.result\.type\}/g, types.getSchemaType(result.schema, json, {title: true, asPath: false, destination: state.destination })) //, baseUrl: options.baseUrl - .replace(/\$\{event\.result\.type\}/, isEventMethod(methodObj) ? types.getSchemaType(result.schema, json, { destination: state.destination, event: true, description: methodObj.result.summary, asPath: false }): '') //, baseUrl: options.baseUrl - .replace(/\$\{method\.result\}/g, generateResult(result.schema, json, templates)) + .replace(/\$\{method\.result\.link\}/g, getLinkForSchema(result.schema, json, {name : result.name})) //, baseUrl: options.baseUrl + .replace(/\$\{method\.result\.type\}/g, types.getSchemaType(result.schema, json, {name: result.name, title: true, asPath: false, destination: state.destination })) //, baseUrl: options.baseUrl + .replace(/\$\{event\.result\.type\}/, isEventMethod(methodObj) ? types.getSchemaType(result.schema, json, { name: result.name, destination: state.destination, event: true, description: methodObj.result.summary, asPath: false }): '') //, baseUrl: options.baseUrl + .replace(/\$\{method\.result\}/g, generateResult(result.schema, json, templates, { name : result.name })) .replace(/\$\{method\.example\.value\}/g, JSON.stringify(methodObj.examples[0].result.value)) .replace(/\$\{method\.alternative\}/g, method.alternative) .replace(/\$\{method\.alternative.link\}/g, '#'+(method.alternative || "").toLowerCase()) @@ -1191,8 +1209,9 @@ function insertExampleMacros(template, examples, method, json, templates) { return template.replace(/\$\{method\.examples\}/g, content) } -function generateResult(result, json, templates) { - const type = types.getSchemaType(result, json, { destination: state.destination, section: state.section }) +function generateResult(result, json, templates, { name = '' } = {}) { + + const type = types.getSchemaType(result, json, { name: name, destination: state.destination, section: state.section }) if (result.type === 'object' && result.properties) { let content = getTemplate('/types/object', templates).split('\n') @@ -1203,13 +1222,13 @@ function generateResult(result, json, templates) { } } - return insertSchemaMacros(content.join('\n'), result.title, result, json) + return insertSchemaMacros(content.join('\n'), name, result, json) } else if (type === 'string' && Array.isArray(result.enum)) { - return insertSchemaMacros(getTemplate('/types/enum', templates), result, json) + return insertSchemaMacros(getTemplate('/types/enum', templates), name, result, json) } else if (result.$ref) { - const link = getLinkForSchema(result, json) + const link = getLinkForSchema(result, json, { name: name}) // if we get a real link use it if (link !== '#') { @@ -1219,18 +1238,18 @@ function generateResult(result, json, templates) { else { const schema = localizeDependencies(result, json) return getTemplate('/types/default', templates) - .replace(/\$\{type\}/, types.getSchemaShape(schema, json, { name: result.$ref.split("/").pop()})) + .replace(/\$\{type\}/, types.getSchemaShape(schema, json, { name: result.$ref.split("/").pop() })) } } else { - return insertSchemaMacros(getTemplate('/types/default', templates), result.title, result, json) + return insertSchemaMacros(getTemplate('/types/default', templates), name, result, json) } } function insertSchemaMacros(template, title, schema, module) { return template.replace(/\$\{property\}/g, title) - .replace(/\$\{type\}/g, types.getSchemaType(schema, module, { destination: state.destination, section: state.section, code: false })) - .replace(/\$\{type.link\}/g, getLinkForSchema(schema, module)) + .replace(/\$\{type\}/g, types.getSchemaType(schema, module, { name: title, destination: state.destination, section: state.section, code: false })) + .replace(/\$\{type.link\}/g, getLinkForSchema(schema, module, { name: title })) .replace(/\$\{description\}/g, schema.description || '') .replace(/\$\{name\}/g, title || '') } @@ -1240,9 +1259,9 @@ function insertParameterMacros(template, param, method, module) { //| `${method.param.name}` | ${method.param.type} | ${method.param.required} | ${method.param.summary} ${method.param.constraints} | let constraints = getSchemaConstraints(param, module) - let type = types.getSchemaType(param.schema, module, { destination: state.destination, section: state.section, code: false, link: false, title: true, asPath: false, expandEnums: false }) //baseUrl: options.baseUrl - let typeLink = getLinkForSchema(param, module) - let jsonType = types.getJsonType(param.schema, module, { destination: state.destination, section: state.section, code: false, link: false, title: true, asPath: false, expandEnums: false }) + let type = types.getSchemaType(param.schema, module, { name: param.name, destination: state.destination, section: state.section, code: false, link: false, title: true, asPath: false, expandEnums: false }) //baseUrl: options.baseUrl + let typeLink = getLinkForSchema(param.schema, module, { name: param.name }) + let jsonType = types.getJsonType(param.schema, module, { name: param.name, destination: state.destination, section: state.section, code: false, link: false, title: true, asPath: false, expandEnums: false }) if (constraints && type) { constraints = '
' + constraints @@ -1255,7 +1274,7 @@ function insertParameterMacros(template, param, method, module) { .replace(/\$\{method.param.required\}/g, param.required || 'false') .replace(/\$\{method.param.type\}/g, type) .replace(/\$\{json.param.type\}/g, jsonType) - .replace(/\$\{method.param.link\}/g, getLinkForSchema(param, module)) //getType(param)) + .replace(/\$\{method.param.link\}/g, getLinkForSchema(param.schema, module, { name: param.name} )) //getType(param)) .replace(/\$\{method.param.constraints\}/g, constraints) //getType(param)) } diff --git a/src/macrofier/index.mjs b/src/macrofier/index.mjs index 89c194e2..f8acada8 100644 --- a/src/macrofier/index.mjs +++ b/src/macrofier/index.mjs @@ -199,8 +199,6 @@ const macrofy = async ( delete outputFiles[file] } }) - - console.log() } // Grab all schema groups w/ a URI string. These came from some external json-schema that was bundled into the OpenRPC @@ -271,4 +269,4 @@ const macrofy = async ( }) } -export default macrofy \ No newline at end of file +export default macrofy