Skip to content

Commit

Permalink
feat (decorators) : add utility and tests for working with decorators (
Browse files Browse the repository at this point in the history
…#333)

* feat (decorators) : add utility and tests for working with decorators

Signed-off-by: Dan Selman <[email protected]>

* fix(decorators) : correct error message

Signed-off-by: Dan Selman <[email protected]>
  • Loading branch information
dselman authored Sep 18, 2020
1 parent 1a0c263 commit 6acbe5a
Show file tree
Hide file tree
Showing 17 changed files with 14,214 additions and 5,155 deletions.
18,777 changes: 13,695 additions & 5,082 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/markdown-cicero/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ module.exports.CiceroMarkModel = require('./lib/externalModels/CiceroMarkModel')
module.exports.CiceroMarkTransformer = require('./lib/CiceroMarkTransformer');
module.exports.FromCiceroEditVisitor = require('./lib/FromCiceroEditVisitor');
module.exports.ToCommonMarkVisitor = require('./lib/ToCommonMarkVisitor');

module.exports.Decorators = require('./lib/Decorators');
1 change: 0 additions & 1 deletion packages/markdown-cicero/lib/CiceroMarkTransformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,6 @@ class CiceroMarkTransformer {
const validJson = this.serializer.fromJSON(json);
return this.serializer.toJSON(validJson);
}

}

module.exports = CiceroMarkTransformer;
83 changes: 83 additions & 0 deletions packages/markdown-cicero/lib/Decorators.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

/**
* A class to retrieve decorators on CiceroMark nodes
*/
class Decorators {
/**
* Construct an instance, based on a CiceroMark node
* Note that decorator arguments must be specified as an
* array of [name (string),value] pairs, even though this is
* not enforced by the Concerto grammar.
* @param {object} node the CiceroMark node
*/
constructor(node) {
this.data = {};
if(node.decorators) {
node.decorators.forEach( (d) => {
if(d.arguments.length % 2 !==0) {
throw new Error('Arguments must be [name, value] pairs');
}
const args = {};
for( let n=0; n < d.arguments.length-1; n=n+2) {
const arg = d.arguments[n];
if(arg.$class && arg.$class !== 'concerto.metamodel.DecoratorString') {
throw new Error(`Argument names must be strings. Found ${arg.$class}`);
}
const argValue = d.arguments[n+1];
args[arg.value] = argValue.$class === 'concerto.metamodel.DecoratorIdentifier' ? argValue.identifier : argValue.value;
}
this.data[d.name] = args;
});
}
}

/**
* Returns true is the decorator is present
* @param {string} decoratorName the name of the decorator
* @returns {boolean} true is the decorator is present
*/
hasDecorator(decoratorName) {
return !!this.data[decoratorName];
}

/**
* Get the arguments for a named decorator
* @param {string} decoratorName the name of the decorator
* @returns {array} an array of arguments, or null
*/
getArguments(decoratorName) {
return this.data[decoratorName];
}

/**
* Get the arguments for a named decorator
* @param {string} decoratorName the name of the decorator
* @param {string} argumentName the name of the decorator argument
* @returns {object} the value of the argument or null if the decorator
* is missing or undefined if the argument is missing
*/
getDecoratorValue(decoratorName, argumentName) {
const args = this.getArguments(decoratorName);
if(args) {
return args[argumentName];
}
return null;
}
}

module.exports = Decorators;
86 changes: 86 additions & 0 deletions packages/markdown-cicero/lib/Decorators.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

// @ts-nocheck
/* eslint-disable no-undef */
'use strict';

const fs = require('fs');
const Decorators = require('./Decorators');

/**
* Load a test node from disk
* @param {string} name the name of the file to load
* @returns {object} the node
*/
function loadNode(name) {
return JSON.parse(fs.readFileSync( __dirname + `/../test/data/decorators/${name}`, 'utf-8'));
}

describe('decorators', () => {
it('handles string decorator', () => {
const decorators = new Decorators( loadNode('string.json'));
expect(decorators.getDecoratorValue( 'Test', 'type')).toBe('value');
});

it('handles boolean decorator', () => {
const decorators = new Decorators( loadNode('boolean.json'));
expect(decorators.getDecoratorValue( 'Test', 'type')).toBe(true);
});

it('handles number decorator', () => {
const decorators = new Decorators( loadNode('number.json'));
expect(decorators.getDecoratorValue( 'Test', 'type')).toBe(3.14);
});

it('handles identifier decorator', () => {
const decorators = new Decorators( loadNode('identifier.json'));
expect(decorators.getDecoratorValue( 'Test', 'type')).toBe('typeIdentifier');
});

it('handles getting a value for a missing decorator', () => {
const decorators = new Decorators( loadNode('string.json'));
expect(decorators.getDecoratorValue( 'Missing', 'type')).toBe(null);
});

it('handles getting a missing value for a decorator', () => {
const decorators = new Decorators( loadNode('string.json'));
expect(decorators.getDecoratorValue( 'Test', 'missing')).toBe(undefined);
});

it('handles mutiple args decorator', () => {
const decorators = new Decorators( loadNode('multi.json'));
expect(decorators.getDecoratorValue( 'Test', 'type')).toBe('value');
expect(decorators.getDecoratorValue( 'Test', 'second')).toBe('value2');
});

it('hasDecorator', () => {
const decorators = new Decorators( loadNode('multi.json'));
expect(decorators.hasDecorator( 'Test')).toBe(true);
});

it('getArguments', () => {
const decorators = new Decorators( loadNode('multi.json'));
expect(decorators.getArguments( 'Test')).toStrictEqual({second: 'value2', type: 'value'});
});

it('fails with odd number of arguments', () => {
expect(() => new Decorators( loadNode('invalid-odd.json'))).toThrow('Arguments must be [name, value] pairs');
});

it('fails with argument names that are not strings', () => {
expect(() => new Decorators( loadNode('invalid-arg-name.json'))).toThrow('Argument names must be strings');
});

});
16 changes: 16 additions & 0 deletions packages/markdown-cicero/test/data/decorators/boolean.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$class": "org.accordproject.templatemark.VariableDefinition",
"decorators": [{
"$class": "concerto.metamodel.Decorator",
"arguments": [{
"$class": "concerto.metamodel.DecoratorString",
"value": "type"
},
{
"$class": "concerto.metamodel.DecoratorBoolean",
"value": true
}
],
"name": "Test"
}]
}
17 changes: 17 additions & 0 deletions packages/markdown-cicero/test/data/decorators/identifier.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$class": "org.accordproject.templatemark.VariableDefinition",
"decorators": [{
"$class": "concerto.metamodel.Decorator",
"arguments": [{
"$class": "concerto.metamodel.DecoratorString",
"value": "type"
},
{
"$class": "concerto.metamodel.DecoratorIdentifier",
"identifier": "typeIdentifier",
"isArray" : false
}
],
"name": "Test"
}]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$class": "org.accordproject.templatemark.VariableDefinition",
"decorators": [{
"$class": "concerto.metamodel.Decorator",
"arguments": [{
"$class": "concerto.metamodel.DecoratorNumber",
"value": 1
},
{
"$class": "concerto.metamodel.DecoratorString",
"value": "value"
}
],
"name": "Test"
}]
}
12 changes: 12 additions & 0 deletions packages/markdown-cicero/test/data/decorators/invalid-odd.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$class": "org.accordproject.templatemark.VariableDefinition",
"decorators": [{
"$class": "concerto.metamodel.Decorator",
"arguments": [{
"$class": "concerto.metamodel.DecoratorString",
"value": "type"
}
],
"name": "Test"
}]
}
24 changes: 24 additions & 0 deletions packages/markdown-cicero/test/data/decorators/multi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$class": "org.accordproject.templatemark.VariableDefinition",
"decorators": [{
"$class": "concerto.metamodel.Decorator",
"arguments": [{
"$class": "concerto.metamodel.DecoratorString",
"value": "type"
},
{
"$class": "concerto.metamodel.DecoratorString",
"value": "value"
},
{
"$class": "concerto.metamodel.DecoratorString",
"value": "second"
},
{
"$class": "concerto.metamodel.DecoratorString",
"value": "value2"
}
],
"name": "Test"
}]
}
16 changes: 16 additions & 0 deletions packages/markdown-cicero/test/data/decorators/number.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$class": "org.accordproject.templatemark.VariableDefinition",
"decorators": [{
"$class": "concerto.metamodel.Decorator",
"arguments": [{
"$class": "concerto.metamodel.DecoratorString",
"value": "type"
},
{
"$class": "concerto.metamodel.DecoratorNumber",
"value": 3.14
}
],
"name": "Test"
}]
}
16 changes: 16 additions & 0 deletions packages/markdown-cicero/test/data/decorators/string.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$class": "org.accordproject.templatemark.VariableDefinition",
"decorators": [{
"$class": "concerto.metamodel.Decorator",
"arguments": [{
"$class": "concerto.metamodel.DecoratorString",
"value": "type"
},
{
"$class": "concerto.metamodel.DecoratorString",
"value": "value"
}
],
"name": "Test"
}]
}
22 changes: 11 additions & 11 deletions packages/markdown-pdf/src/ToPdfMakeVisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

'use strict';

const { Decorators } = require('@accordproject/markdown-cicero');

/**
* Unquote strings
* @param {string} value - the string
Expand Down Expand Up @@ -153,20 +155,18 @@ class ToPdfMakeVisitor {
visit(thing, parameters) {

// the style defaults to the name of the type
let style = thing.getType();
let decoratorStyle = null;

// if the type has an explicit PdfStyle decorator, then we use it
if( thing.decorators ) {
const pdfStyle = thing.decorators.filter( d => d.name === 'PdfStyle');
if( pdfStyle.length > 0 ) {
if(pdfStyle[0].arguments && pdfStyle[0].arguments.length === 1) {
style = pdfStyle[0].arguments[0].value;
}
}
// if the type has an explicit Pdf style decorator, then we use it
try {
const decorators = new Decorators(thing);
decoratorStyle = decorators.getDecoratorValue( 'Pdf', 'style');
}
catch(error) {
console.log(error);
}

let result = {
style
style : decoratorStyle ? decoratorStyle : thing.getType()
};

switch(thing.getType()) {
Expand Down
Loading

0 comments on commit 6acbe5a

Please sign in to comment.