From ec11703951809a4bb29b07766d815dc905d2dbdc Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Mon, 26 Jan 2026 17:02:24 +0100 Subject: [PATCH 1/5] [csolution rpc]: Add method to report context info --- api/csolution-openapi.yml | 52 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/api/csolution-openapi.yml b/api/csolution-openapi.yml index 46cb27f..885f1f2 100644 --- a/api/csolution-openapi.yml +++ b/api/csolution-openapi.yml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: csolution rpc - version: 0.0.7 + version: 0.0.8 description: Specification of remote procedure call methods for CMSIS csolution integration license: name: Apache 2.0 @@ -87,6 +87,17 @@ paths: '200': description: OK content: {application/json: {schema: {$ref: '#/components/schemas/GetUsedItemsResponse'}}} + /rpc/GetContextInfo: + post: + summary: Get combined context info (device, board, variables, components and packs used() + description: Get used items + tags: [/rpc] + requestBody: + content: {application/json: {schema: {$ref: '#/components/schemas/GetContextInfoRequest'}}} + responses: + '200': + description: OK + content: {application/json: {schema: {$ref: '#/components/schemas/GetContextInfoResponse'}}} /rpc/GetPacksInfo: post: summary: Get packs information @@ -324,6 +335,9 @@ components: origin: type: string description: Originating YAML file + overview: + type: string + description: Brief pack overview (if resolved) selected: type: boolean description: Flag to indicate if reference is selected @@ -724,6 +738,22 @@ components: required: - components - packs + ContextInfo: + allOf: + - $ref: '#/components/schemas/UsedItems' + - properties: + board: + $ref: '#/components/schemas/Board' + device: + $ref: '#/components/schemas/Device' + variables: + type: object + additionalProperties: + type: string + description: Resolved context variables + required: + - device + - variables LogMessages: allOf: - $ref: '#/components/schemas/SuccessResult' @@ -1127,6 +1157,26 @@ components: - properties: result: $ref: '#/components/schemas/UsedItems' + GetContextInfoRequest: + allOf: + - $ref: '#/x-jsonrpc-envelope-request-with-params' + - properties: + method: + type: string + const: GetContextInfo + params: + type: object + properties: + context: + type: string + required: + - context + GetContextInfoResponse: + allOf: + - $ref: '#/x-jsonrpc-envelope-response' + - properties: + result: + $ref: '#/components/schemas/ContextInfo' GetDeviceListRequest: allOf: - $ref: '#/x-jsonrpc-envelope-request-with-params' From 4d7044e0e071ccc739bdf204b4fee4964107a396 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Mon, 26 Jan 2026 18:03:45 +0100 Subject: [PATCH 2/5] Codegen changes (codegen.ts): Modified collectStruct to handle types with additionalProperties Modified collectStructs to process these types Updated C++ and TypeScript generation to create type aliases instead of trying to inline them Schema is updated to use Variables type. Description is changed --- api/csolution-openapi.yml | 19 +++++---- codegen/src/codegen.ts | 82 ++++++++++++++++++++++++++------------- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/api/csolution-openapi.yml b/api/csolution-openapi.yml index 885f1f2..be9b44e 100644 --- a/api/csolution-openapi.yml +++ b/api/csolution-openapi.yml @@ -89,8 +89,8 @@ paths: content: {application/json: {schema: {$ref: '#/components/schemas/GetUsedItemsResponse'}}} /rpc/GetContextInfo: post: - summary: Get combined context info (device, board, variables, components and packs used() - description: Get used items + summary: Get combined context info + description: Get combined context info (device, board, variables, components and packs used) tags: [/rpc] requestBody: content: {application/json: {schema: {$ref: '#/components/schemas/GetContextInfoRequest'}}} @@ -738,6 +738,11 @@ components: required: - components - packs + Variables: + type: object + additionalProperties: + type: string + description: Resolved context variables ContextInfo: allOf: - $ref: '#/components/schemas/UsedItems' @@ -747,10 +752,7 @@ components: device: $ref: '#/components/schemas/Device' variables: - type: object - additionalProperties: - type: string - description: Resolved context variables + $ref: '#/components/schemas/Variables' required: - device - variables @@ -948,10 +950,7 @@ components: - $ref: '#/components/schemas/SuccessResult' - properties: variables: - type: object - additionalProperties: - type: string - description: Resolved context variables + $ref: '#/components/schemas/Variables' required: - variables GetVariablesRequest: diff --git a/codegen/src/codegen.ts b/codegen/src/codegen.ts index fe74710..a417fd3 100644 --- a/codegen/src/codegen.ts +++ b/codegen/src/codegen.ts @@ -246,6 +246,19 @@ using namespace jsonrpccxx;\n`; optional: obj.required ? !(obj.required as any).includes(element) : true, }); } + } else if (obj.additionalProperties) { + // Handle types defined with additionalProperties (e.g., map/record types) + const {cpp, ts} = this.getType(name, obj.additionalProperties); + this.structs[name] = { + description: obj.description, + members: [{ + name: '', + cppType: `map`, + tsType: `Record`, + description: obj.description, + optional: false, + }] + }; } } @@ -257,6 +270,9 @@ using namespace jsonrpccxx;\n`; this.collectStructs(this.getTypeName(name), item); } this.collectStruct(parent, obj.items ?? obj); + } else if (obj.additionalProperties) { + // Handle objects with additionalProperties but no properties (e.g., Variables) + this.collectStruct(parent, obj); } if (obj.allOf && Array.isArray(obj.allOf)) { for (const item of obj.allOf) { @@ -395,24 +411,29 @@ using namespace jsonrpccxx;\n`; const forwardDeclaration = new Set; //TODO: content += `${struct.description ? ` // ${struct.description}\n` : ''}`; if (struct.members) { - structContent += ` struct ${name}`; - if (struct.extends) { - const baseClasses = (struct.extends.map(s => `public ${s}`)).join(', '); - structContent += ` : ${baseClasses}`; - } - structContent +=` {\n`; - for (const element of struct.members) { - // need forward declarations - const s = element.cppType.match(/(?:vector<)?(\w+)>?/); - if (s && s[1] in this.structs && !declaredStructs.includes(s[1])) { - forwardDeclaration.add(s[1]); + // Check if this is a type alias (single member with empty name) + if (struct.members.length === 1 && struct.members[0].name === '') { + structContent += ` using ${name} = ${struct.members[0].cppType};\n`; + } else { + structContent += ` struct ${name}`; + if (struct.extends) { + const baseClasses = (struct.extends.map(s => `public ${s}`)).join(', '); + structContent += ` : ${baseClasses}`; } - const cppStruct = `${element.optional ? `optional<${element.cppType}>` : - `${element.cppType}`} ${this.kebabToCamel(element.name)};`; - structContent += ` ${cppStruct}\n`; - //TODO: content += `${element.description ? ` // ${element.description}` : ``}\n`; + structContent +=` {\n`; + for (const element of struct.members) { + // need forward declarations + const s = element.cppType.match(/(?:vector<)?(\w+)>?/); + if (s && s[1] in this.structs && !declaredStructs.includes(s[1])) { + forwardDeclaration.add(s[1]); + } + const cppStruct = `${element.optional ? `optional<${element.cppType}>` : + `${element.cppType}`} ${this.kebabToCamel(element.name)};`; + structContent += ` ${cppStruct}\n`; + //TODO: content += `${element.description ? ` // ${element.description}` : ``}\n`; + } + structContent += ` };\n`; } - structContent += ` };\n`; } else { if (struct.extends) { const baseClasses = struct.extends.join(', '); @@ -429,7 +450,7 @@ using namespace jsonrpccxx;\n`; content += `\n${this.cppToJsonTemplates}`; for (const name in this.structs) { const struct = this.structs[name]; - if (struct.members) { + if (struct.members && !(struct.members.length === 1 && struct.members[0].name === '')) { content += ` inline void to_json(nlohmann::json& j, const ${name}& s) {\n`; content += this.genParentJsonTypeMap('to_json', struct); content += this.genJsonTypeMap('to_json', struct.members); @@ -441,7 +462,7 @@ using namespace jsonrpccxx;\n`; content += `\n${this.cppFromJsonTemplates}`; for (const name in this.structs) { const struct = this.structs[name]; - if (struct.members) { + if (struct.members && !(struct.members.length === 1 && struct.members[0].name === '')) { content += ` inline void from_json(const nlohmann::json& j, ${name}& s) {\n`; content += this.genParentJsonTypeMap('from_json', struct); content += this.genJsonTypeMap('from_json', struct.members); @@ -465,17 +486,22 @@ ${this.genCppNamespace()}\n${this.genCppClass()}\n${this.cppFooter}\n`; for (const name in this.structs) { const struct = this.structs[name]; if (struct.members) { - content += `export interface ${name}`; - if (struct.extends) { - const baseClasses = struct.extends.join(', '); - content += ` extends ${baseClasses}`; - } - content += ` {\n`; - for (const element of struct.members) { - const tsInterface = `${this.quoteIfDashed(element.name)}${element.optional ? '?' : ''}: ${element.tsType},`; - content += ` ${tsInterface}\n`; + // Check if this is a type alias (single member with empty name) + if (struct.members.length === 1 && struct.members[0].name === '') { + content += `export type ${name} = ${struct.members[0].tsType};\n`; + } else { + content += `export interface ${name}`; + if (struct.extends) { + const baseClasses = struct.extends.join(', '); + content += ` extends ${baseClasses}`; + } + content += ` {\n`; + for (const element of struct.members) { + const tsInterface = `${this.quoteIfDashed(element.name)}${element.optional ? '?' : ''}: ${element.tsType},`; + content += ` ${tsInterface}\n`; + } + content += `}\n`; } - content += `}\n`; } else { if (struct.extends) { const baseClasses = struct.extends.join(', '); From d2e5861ece79df21e7434ff31e73a74bf177f994 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 27 Jan 2026 10:12:19 +0100 Subject: [PATCH 3/5] Extended ConfigInfo --- api/csolution-openapi.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/api/csolution-openapi.yml b/api/csolution-openapi.yml index be9b44e..612eb38 100644 --- a/api/csolution-openapi.yml +++ b/api/csolution-openapi.yml @@ -299,6 +299,10 @@ components: description: optional error/warning/info message required: - success + Attributes: + type: object + additionalProperties: + type: string Common: type: object properties: @@ -405,9 +409,8 @@ components: type: string description: Processor core type attributes: - type: object - additionalProperties: - type: string + $ref: '#/components/schemas/Attributes' + description: Processor attributes required: - core Memory: @@ -751,10 +754,18 @@ components: $ref: '#/components/schemas/Board' device: $ref: '#/components/schemas/Device' + pname: + type: string + description: Processor name used in context variables: $ref: '#/components/schemas/Variables' + attributes: + $ref: '#/components/schemas/Attributes' + description: RTE target attributes required: - device + - pname + - attributes - variables LogMessages: allOf: From bf7f56702c7c4e6ac962cd4fecf14391ebc0fd1f Mon Sep 17 00:00:00 2001 From: Daniel Brondani Date: Tue, 27 Jan 2026 15:08:43 +0100 Subject: [PATCH 4/5] Update codegen --- codegen/src/codegen.ts | 102 +++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/codegen/src/codegen.ts b/codegen/src/codegen.ts index a417fd3..ed4f1e7 100644 --- a/codegen/src/codegen.ts +++ b/codegen/src/codegen.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Arm Limited. All rights reserved. + * Copyright (c) 2025-2026 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ @@ -44,10 +44,16 @@ export interface Member { optional?: boolean; } +export interface CustomType { + cppType: string; + tsType: string; +} + export interface Struct { description?: string; members?: Member[]; extends?: string[]; + customType?: CustomType; } export interface Function { @@ -66,7 +72,7 @@ export class Codegen { readonly header = `/* - * Copyright (c) 2025 Arm Limited. All rights reserved. + * Copyright (c) 2025-2026 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * @@ -246,19 +252,6 @@ using namespace jsonrpccxx;\n`; optional: obj.required ? !(obj.required as any).includes(element) : true, }); } - } else if (obj.additionalProperties) { - // Handle types defined with additionalProperties (e.g., map/record types) - const {cpp, ts} = this.getType(name, obj.additionalProperties); - this.structs[name] = { - description: obj.description, - members: [{ - name: '', - cppType: `map`, - tsType: `Record`, - description: obj.description, - optional: false, - }] - }; } } @@ -271,8 +264,11 @@ using namespace jsonrpccxx;\n`; } this.collectStruct(parent, obj.items ?? obj); } else if (obj.additionalProperties) { - // Handle objects with additionalProperties but no properties (e.g., Variables) - this.collectStruct(parent, obj); + // Handle types defined with additionalProperties (e.g., map/record types) + const {cpp, ts} = this.getType(parent, obj); + this.structs[parent] = { + description: obj.description, + customType: { cppType: cpp, tsType: ts } }; } if (obj.allOf && Array.isArray(obj.allOf)) { for (const item of obj.allOf) { @@ -410,30 +406,28 @@ using namespace jsonrpccxx;\n`; let structContent = ''; const forwardDeclaration = new Set; //TODO: content += `${struct.description ? ` // ${struct.description}\n` : ''}`; + if (struct.customType) { + structContent += ` using ${name} = ${struct.customType.cppType};\n`; + } if (struct.members) { - // Check if this is a type alias (single member with empty name) - if (struct.members.length === 1 && struct.members[0].name === '') { - structContent += ` using ${name} = ${struct.members[0].cppType};\n`; - } else { - structContent += ` struct ${name}`; - if (struct.extends) { - const baseClasses = (struct.extends.map(s => `public ${s}`)).join(', '); - structContent += ` : ${baseClasses}`; - } - structContent +=` {\n`; - for (const element of struct.members) { - // need forward declarations - const s = element.cppType.match(/(?:vector<)?(\w+)>?/); - if (s && s[1] in this.structs && !declaredStructs.includes(s[1])) { - forwardDeclaration.add(s[1]); - } - const cppStruct = `${element.optional ? `optional<${element.cppType}>` : - `${element.cppType}`} ${this.kebabToCamel(element.name)};`; - structContent += ` ${cppStruct}\n`; - //TODO: content += `${element.description ? ` // ${element.description}` : ``}\n`; + structContent += ` struct ${name}`; + if (struct.extends) { + const baseClasses = (struct.extends.map(s => `public ${s}`)).join(', '); + structContent += ` : ${baseClasses}`; + } + structContent +=` {\n`; + for (const element of struct.members) { + // need forward declarations + const s = element.cppType.match(/(?:vector<)?(\w+)>?/); + if (s && s[1] in this.structs && !declaredStructs.includes(s[1])) { + forwardDeclaration.add(s[1]); } - structContent += ` };\n`; + const cppStruct = `${element.optional ? `optional<${element.cppType}>` : + `${element.cppType}`} ${this.kebabToCamel(element.name)};`; + structContent += ` ${cppStruct}\n`; + //TODO: content += `${element.description ? ` // ${element.description}` : ``}\n`; } + structContent += ` };\n`; } else { if (struct.extends) { const baseClasses = struct.extends.join(', '); @@ -450,7 +444,7 @@ using namespace jsonrpccxx;\n`; content += `\n${this.cppToJsonTemplates}`; for (const name in this.structs) { const struct = this.structs[name]; - if (struct.members && !(struct.members.length === 1 && struct.members[0].name === '')) { + if (struct.members) { content += ` inline void to_json(nlohmann::json& j, const ${name}& s) {\n`; content += this.genParentJsonTypeMap('to_json', struct); content += this.genJsonTypeMap('to_json', struct.members); @@ -462,7 +456,7 @@ using namespace jsonrpccxx;\n`; content += `\n${this.cppFromJsonTemplates}`; for (const name in this.structs) { const struct = this.structs[name]; - if (struct.members && !(struct.members.length === 1 && struct.members[0].name === '')) { + if (struct.members) { content += ` inline void from_json(const nlohmann::json& j, ${name}& s) {\n`; content += this.genParentJsonTypeMap('from_json', struct); content += this.genJsonTypeMap('from_json', struct.members); @@ -485,23 +479,21 @@ ${this.genCppNamespace()}\n${this.genCppClass()}\n${this.cppFooter}\n`; let content = ''; for (const name in this.structs) { const struct = this.structs[name]; + if (struct.customType) { + content += `export type ${name} = ${struct.customType.tsType};\n`; + } if (struct.members) { - // Check if this is a type alias (single member with empty name) - if (struct.members.length === 1 && struct.members[0].name === '') { - content += `export type ${name} = ${struct.members[0].tsType};\n`; - } else { - content += `export interface ${name}`; - if (struct.extends) { - const baseClasses = struct.extends.join(', '); - content += ` extends ${baseClasses}`; - } - content += ` {\n`; - for (const element of struct.members) { - const tsInterface = `${this.quoteIfDashed(element.name)}${element.optional ? '?' : ''}: ${element.tsType},`; - content += ` ${tsInterface}\n`; - } - content += `}\n`; + content += `export interface ${name}`; + if (struct.extends) { + const baseClasses = struct.extends.join(', '); + content += ` extends ${baseClasses}`; + } + content += ` {\n`; + for (const element of struct.members) { + const tsInterface = `${this.quoteIfDashed(element.name)}${element.optional ? '?' : ''}: ${element.tsType},`; + content += ` ${tsInterface}\n`; } + content += `}\n`; } else { if (struct.extends) { const baseClasses = struct.extends.join(', '); From 5e41832af4bfa178053d1a891dbd3e93cc56a717 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 27 Jan 2026 15:18:03 +0100 Subject: [PATCH 5/5] Remove overview field from PackReference (not needed) --- api/csolution-openapi.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/csolution-openapi.yml b/api/csolution-openapi.yml index 612eb38..bb95ac0 100644 --- a/api/csolution-openapi.yml +++ b/api/csolution-openapi.yml @@ -339,9 +339,6 @@ components: origin: type: string description: Originating YAML file - overview: - type: string - description: Brief pack overview (if resolved) selected: type: boolean description: Flag to indicate if reference is selected