Skip to content

Commit 53f09e6

Browse files
authored
feat(concerto-core): implement YAML to JSON conversion for DCS (#1044)
* feat(dcsconverter): implement yaml to json conversion - updated test files considering full coverage - updated changelog and type files Signed-off-by: fuyalasmit <[email protected]> * update JSDoc and api changelog files Signed-off-by: fuyalasmit <[email protected]> --------- Signed-off-by: fuyalasmit <[email protected]>
1 parent 271ceaa commit 53f09e6

File tree

8 files changed

+330
-14
lines changed

8 files changed

+330
-14
lines changed

packages/concerto-core/api.txt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,8 @@ class Concerto {
5656
+ string getNamespace(obj)
5757
}
5858
+ object setCurrentTime()
59-
+ object handleTarget()
60-
+ object handleArguments()
61-
+ object handleDecorator()
62-
+ object handleCommands()
63-
+ string jsonToYaml() throws Error
59+
+ string jsonToYaml()
60+
+ object yamlToJson()
6461
class DecoratorManager {
6562
+ ModelManager validate(decoratorCommandSet,ModelFile[]) throws Error
6663
+ object migrateTo(decoratorCommandSet,string)
@@ -76,6 +73,7 @@ class DecoratorManager {
7673
+ void executePropertyCommand(property,command)
7774
+ Boolean isNamespaceTargetEnabled(boolean?)
7875
+ string jsonToYaml(object)
76+
+ object yamlToJson(string)
7977
}
8078
+ string[] intersect()
8179
+ boolean isUnversionedNamespaceEqual()

packages/concerto-core/changelog.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
# Note that the latest public API is documented using JSDocs and is available in api.txt.
2525
#
2626

27-
Version 3.22.0 {59de1f67703a76ab4a0f0c986775e889} 2025-07-12
27+
Version 3.22.0 {677eac41f1ef471977d3e301e46ef480} 2025-07-26
2828
- added jsonToYaml method in DecoratorManager
29+
- added yamlToJson method in DecoratorManager
2930

3031
Version 3.20.5 {a18e77c836e19a4badcbe83d6c7e7c1e} 2025-02-03
3132
- vocabulary support for namespace scoped decorators

packages/concerto-core/lib/dcsconverter.js

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
const yaml = require('yaml');
1818
const ModelUtil = require('./modelutil');
19+
const { MetaModelNamespace } = require('@accordproject/concerto-metamodel');
1920

2021
/**
2122
* handles the target field of a command
2223
* @param {object} target the value of target
2324
* @returns {object} the simplified target object
25+
* @private
2426
*/
2527
function handleTarget(target){
2628
const targetKeys = Object.keys(target);
@@ -42,12 +44,13 @@ function handleTarget(target){
4244
* @param {object} [argument.type] the type identifier for type reference arguments
4345
* @param {boolean} [argument.isArray] whether the type reference is an array
4446
* @returns {object} simplified argument object
47+
* @private
4548
*/
4649
function handleArguments(argument){
4750
const mapClassToType = {
48-
'[email protected].DecoratorString': 'String',
49-
'[email protected].DecoratorNumber': 'Number',
50-
'[email protected].DecoratorBoolean': 'Boolean',
51+
[`${MetaModelNamespace}.DecoratorString`]: 'String',
52+
[`${MetaModelNamespace}.DecoratorNumber`]: 'Number',
53+
[`${MetaModelNamespace}.DecoratorBoolean`]: 'Boolean',
5154
};
5255
if (argument.$class.endsWith('TypeReference')) {
5356
return {
@@ -71,6 +74,7 @@ function handleArguments(argument){
7174
* @param {string} decorator.name the name of the decorator
7275
* @param {object[]} [decorator.arguments] the list of arguments
7376
* @returns {object} simplified decorator object with name and arguments
77+
* @private
7478
*/
7579
function handleDecorator(decorator){
7680
return {
@@ -88,6 +92,7 @@ function handleDecorator(decorator){
8892
* @param {object} command.target the target to apply decorator to
8993
* @param {object} command.decorator the decorator to apply
9094
* @returns {object} simplified commands object
95+
* @private
9196
*/
9297
function handleCommands(command){
9398
return {
@@ -101,7 +106,6 @@ function handleCommands(command){
101106
* converts DCS JSON to YAML string
102107
* @param {object} dcsJson the DCS JSON as parsed object
103108
* @returns {string} the DCS YAML string
104-
* @throws {Error} if the input is not a valid DCS JSON
105109
*/
106110
function jsonToYaml(dcsJson){
107111
const dcsNamespace = ModelUtil.getNamespace(dcsJson.$class);
@@ -121,4 +125,95 @@ function jsonToYaml(dcsJson){
121125
return yamlString;
122126
}
123127

124-
module.exports = { jsonToYaml };
128+
129+
/**
130+
* handles each argument of the decorator
131+
* converts simplified argument objects back to full JSON representation
132+
* @param {string} MetaModelNamespace - the metamodel namespace
133+
* @param {object} argument - the simplified argument object
134+
* @param {string} [argument.type] - the argument type for primitive values
135+
* @param {*} [argument.value] - the argument value
136+
* @param {object} [argument.typeReference] - the type reference object for complex types
137+
* @returns {object} - the fully qualified argument object after restoring required fields
138+
* @private
139+
*/
140+
function restoreArguments(MetaModelNamespace, argument){
141+
const mapTypeToClass = {
142+
'String': `${MetaModelNamespace}.DecoratorString`,
143+
'Number': `${MetaModelNamespace}.DecoratorNumber`,
144+
'Boolean': `${MetaModelNamespace}.DecoratorBoolean`,
145+
};
146+
if ( Object.keys(argument)[0] === 'typeReference' ) {
147+
return {
148+
$class: ModelUtil.getFullyQualifiedName(MetaModelNamespace, 'DecoratorTypeReference'),
149+
type: {
150+
$class: ModelUtil.getFullyQualifiedName(MetaModelNamespace, 'TypeIdentifier'),
151+
name: argument.typeReference.name,
152+
... ( argument.typeReference.namespace !== undefined ? { namespace: argument.typeReference.namespace } : {} ),
153+
... ( argument.typeReference.resolvedName !== undefined ? { resolvedName: argument.typeReference.resolvedName } : {} ),
154+
},
155+
isArray: argument.typeReference.isArray
156+
};
157+
}
158+
return {
159+
$class: mapTypeToClass[argument.type],
160+
value: argument.type === 'String' ? String(argument.value) : argument.value ,
161+
};
162+
}
163+
164+
165+
/**
166+
* handles the decorator of each command for yaml to json
167+
* @param {object} decorator - the decorator to convert
168+
* @returns {object} - the decorator object after restoring required fields
169+
* @private
170+
*/
171+
function restoreDecorator(decorator){
172+
return {
173+
$class: ModelUtil.getFullyQualifiedName(MetaModelNamespace, 'Decorator'),
174+
name: decorator.name,
175+
arguments: decorator.arguments ? decorator.arguments.map((argument) => restoreArguments(MetaModelNamespace, argument)) : [],
176+
};
177+
}
178+
179+
180+
/**
181+
* handles the command for yaml to json method
182+
* @param {string} dcsNamespace - the namespace of the DCS
183+
* @param {object} command - the command to convert
184+
* @returns {object} - the command object after restoring required fields
185+
* @private
186+
*/
187+
function restoreCommands(dcsNamespace, command){
188+
return {
189+
$class: ModelUtil.getFullyQualifiedName(dcsNamespace, 'Command'),
190+
type: command.action,
191+
target: {
192+
$class: ModelUtil.getFullyQualifiedName(dcsNamespace, 'CommandTarget'),
193+
... command.target
194+
},
195+
decorator: restoreDecorator(command.decorator)
196+
};
197+
}
198+
199+
200+
/**
201+
* converts DCS YAML string to JSON format
202+
* @param {string} yamlString the YAML string to convert
203+
* @returns {object} the DCS JSON
204+
*/
205+
function yamlToJson(yamlString){
206+
const parsedJson = yaml.parse(yamlString);
207+
const dcsNamespace = 'org.accordproject.decoratorcommands@' + parsedJson.decoratorCommandsVersion;
208+
const dcsJson = {
209+
$class: ModelUtil.getFullyQualifiedName(dcsNamespace, 'DecoratorCommandSet'),
210+
name: parsedJson.name,
211+
version: parsedJson.version,
212+
commands: parsedJson.commands.map((command) => restoreCommands(dcsNamespace, command)),
213+
};
214+
215+
return dcsJson;
216+
}
217+
218+
219+
module.exports = { jsonToYaml, yamlToJson };

packages/concerto-core/lib/decoratormanager.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const rfdc = require('rfdc')({
2828
proto: false,
2929
});
3030

31-
const { jsonToYaml } = require('./dcsconverter');
31+
const { jsonToYaml, yamlToJson } = require('./dcsconverter');
3232

3333
// Types needed for TypeScript generation.
3434
/* eslint-disable no-unused-vars */
@@ -864,6 +864,19 @@ class DecoratorManager {
864864
this.validate(jsonInput);
865865
return jsonToYaml(jsonInput);
866866
}
867+
868+
/**
869+
* converts DCS YAML string into JSON object
870+
* validates the output DCS JSON against the DCS model
871+
* @param {string} yamlInput the DCS JSON as parsed object
872+
* @return {object} the corresponding JSON object
873+
*/
874+
static yamlToJson(yamlInput){
875+
const jsonOutput = yamlToJson(yamlInput);
876+
this.validate(jsonOutput);
877+
return jsonOutput;
878+
}
879+
867880
}
868881

869882
module.exports = DecoratorManager;

0 commit comments

Comments
 (0)