diff --git a/packages/concerto-core/lib/introspect/decorator.js b/packages/concerto-core/lib/introspect/decorator.js index 557be91b7..775d2d299 100644 --- a/packages/concerto-core/lib/introspect/decorator.js +++ b/packages/concerto-core/lib/introspect/decorator.js @@ -159,6 +159,25 @@ class Decorator { this.handleError(validationOptions.invalidDecorator, err); } break; + case 'DecoratorJSON': { + if (argType !== 'object') { + const err = `Decorator ${this.getName()} has invalid decorator argument. Expected object for JSON. Found ${argType}, with value ${JSON.stringify(arg)}`; + this.handleError(validationOptions.invalidator, err); + } + const keys = Object.keys(arg); + keys.forEach(key => { + if (typeof key !=='string') { + const err = `Decorator ${this.getName()} has an invalid key in the JSON object. Expected string, but found ${typeof key}.`; + this.handleError(validationOptions.invalidDecorator, err); + } + const valueType = typeof arg[key]; + if (!['string', 'number', 'boolean'].includes(valueType)) { + const err = `Decorator ${this.getName()} has an invalid value type in the JSON object, Expected string, number, or boolean, but found ${valueType} for key ${key}.`; + this.handleError(validationOptions.invalidDecorator, err); + } + }); + break; + } default: { if (argType !== 'object' || arg?.type !== 'Identifier') { const err = `Decorator ${this.getName()} has invalid decorator argument. Expected object. Found ${argType}, with value ${JSON.stringify(arg)}`; diff --git a/packages/concerto-cto/lib/parser.pegjs b/packages/concerto-cto/lib/parser.pegjs index 845b74535..b0bf7a48c 100644 --- a/packages/concerto-cto/lib/parser.pegjs +++ b/packages/concerto-cto/lib/parser.pegjs @@ -918,11 +918,29 @@ DecoratorIdentifier = } } +DecoratorJSON = + "{" _ pairs:(KeyValue ("," _ KeyValue)*)? _ "}" { + return { + $class: "concerto.metamodel@1.0.0.DecoratorJSON", + value: pairs ? pairs.reduce(obj, pair) => { + obj[pair.key] = pair.value; + return obj; + }, {} : {}, + ...buildRange(location()) + }; + } + +KeyValue = + key:StringLiteral _ ":" _ value:DecoratorLiteral { + return { key: key.value, value:value }; + } + DecoratorLiteral = DecoratorString / DecoratorBoolean / DecoratorNumber / DecoratorIdentifier + / DecoratorJSON DecoratorArguments = "(" __ first:(d:DecoratorLiteral __ "," __ {return d;})* last:DecoratorLiteral? __ ")" {