From d0a22861c0900f25a9946ab510cfb794005d037a Mon Sep 17 00:00:00 2001 From: "Thomas, Eiko" Date: Mon, 22 Oct 2018 21:35:33 +0200 Subject: [PATCH 1/4] type names to camel-case, add and remove tags from type per config --- README.md | 32 +++++++ Releases.md | 6 ++ .../groovy/de/lisaplus/atlas/DoCodeGen.groovy | 87 +++++++++++++++++++ .../atlas/builder/helper/BuildHelper.groovy | 7 +- .../atlas/codegen/MultiFileGenarator.groovy | 15 +++- .../groovy/de/lisaplus/atlas/Model.groovy | 4 +- .../test/jsonschema/JsonSchemaBuilder.groovy | 12 +-- .../test/jsonschema/MultiTypeSchema.groovy | 8 +- .../atlas/codegen/test/JavaBeans.groovy | 52 ++++++++++- 9 files changed, 206 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 71498db..6e098c0 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,38 @@ gradle myRun -PmyArgs="-o,/tmp/test_beans,-m,src/test/resources/test_schemas/mul -gp,destFileNameExt=java,-gp,packageName=de.sw.atlas.test" ``` ### Usage of the release + +```bash +./jsonCodeGen.sh +Usage: de.lisaplus.atlas.DoCodeGen [options] + Options: + -at, --add-tag + add a text as tag to a specific type, f.e. -at User=unused + Default: [] + -b, --black-list + black listed type, multiple usage possible + Default: [] + -g, --generator + generator that are used with the model. This parameter can be used + multiple times + Default: [] + -gp, --generator-parameter + special parameter that are passed to template via maps + Default: [] + -h, --help + + * -m, --model + Path to JSON schema to parse + * -o, --outputBase + Base directory for the output + -rt, --remove-tag + remove a tag from a specific type, f.e. -at User=unused + Default: [] + -w, --white-list + white listed type, multiple usage possible + Default: [] +``` + After you built a release with gradle or you download a release bundle you can start the program with the contained start script. If you start it with the help option you get a full description of the possible parameters diff --git a/Releases.md b/Releases.md index ed80dc3..a0e0b3f 100644 --- a/Releases.md +++ b/Releases.md @@ -1,3 +1,9 @@ +## 0.8.0 +- command line switches for type black- and white-lists +- command line switch to add tags to types +- command line switch to remove a tag from types +- enforce camel-case type names in models + ## 0.7.5 - deep copy functions for types - introduce pure array type to handle definitions where arrays contain only arrays, f.e. geoJson Polygons diff --git a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy index 723276a..41e5d4b 100644 --- a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy +++ b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy @@ -31,21 +31,60 @@ import org.slf4j.LoggerFactory * Created by eiko on 30.05.17. */ class DoCodeGen { + /** + * model file + */ @Parameter(names = [ '-m', '--model' ], description = "Path to JSON schema to parse", required = true) String model + /** + * Base directory for the output + */ @Parameter(names = [ '-o', '--outputBase' ], description = "Base directory for the output", required = true) String outputBaseDir + /** + * Generator to use + */ @Parameter(names = ['-g', '--generator'], description = "generator that are used with the model. This parameter can be used multiple times") List generators = [] + /** + * Generator parameter + */ @Parameter(names = ['-gp', '--generator-parameter'], description = "special parameter that are passed to template via maps") List generator_parameters = [] + /** + * Type white list + */ + @Parameter(names = ['-w', '--white-list'], description = "white listed type, multiple usage possible") + List whiteListed = [] + + /** + * Type black list + */ + @Parameter(names = ['-b', '--black-list'], description = "black listed type, multiple usage possible") + List blackListed = [] + + /** + * Print help + */ @Parameter(names = ['-h','--help'], help = true) boolean help = false + /** + * List of type-name tag-text tuple, The tags will be merged after initialization with the object tree + */ + @Parameter(names = ['-at', '--add-tag'], description = "add a text as tag to a specific type, f.e. -at User=unused") + List typeAddTagList = [] + + /** + * List of type-name tag-text tuple, after initialization the tags will be removed for the given types in the object tree + */ + @Parameter(names = ['-rt', '--remove-tag'], description = "remove a tag from a specific type, f.e. -at User=unused") + List typeRemoveTagList = [] + static void main(String ... args) { DoCodeGen doCodeGen = new DoCodeGen() try { @@ -88,8 +127,11 @@ class DoCodeGen { System.exit(1) } Model dataModel = builder.buildModel(modelFile) + adjustTagsForModel(dataModel) // convert extra generator parameter to a map Map extraParameters = getMapFromGeneratorParams(generator_parameters) + extraParameters['blackListed']=blackListed + extraParameters['whiteListed']=whiteListed if (generators==null || generators.isEmpty()) { log.warn('no generators configured - skip') } @@ -290,6 +332,51 @@ class DoCodeGen { print (usageFile.getText()) } + private void adjustTagsForModel(Model dataModel) { + Map> typeAddTagMap = mapFromConfig(typeAddTagList) + Map> typeRemoveTagMap = mapFromConfig(typeRemoveTagList) + dataModel.types.each { type -> + // remove undesired tags + List tagsToRemove = typeRemoveTagMap[type.name] + if (tagsToRemove) { + // remove tags + tagsToRemove.each { tag -> + type.tags.remove(tag) + } + } + List tagsToAdd = typeAddTagMap[type.name] + if (tagsToAdd) { + // add tags + tagsToAdd.each { tag -> + if (!type.tags.contains(tag)) { + type.tags.add(tag) + } + } + } + } + } + + private Map> mapFromConfig(List config) { + Map> ret = [:] + if (!config) return ret + config.each { typeTagStr -> + def typeTagArray = typeTagStr.split('=') + if (typeTagArray.length>2) { + println "[mapFromConfig] - wrong type/tag-tuple: $typeTagStr" + return + } + def typeName = typeTagArray[0].trim() + def tag = typeTagArray[1].trim() + List alreadyExistingValues = ret.get[typeName] + if (alreadyExistingValues && (!alreadyExistingValues.contains(tag))) { + alreadyExistingValues.add(tag) + } + else { + ret[typeName] = [tag] + } + } + return ret + } private static final Logger log=LoggerFactory.getLogger(DoCodeGen.class) } diff --git a/src/main/groovy/de/lisaplus/atlas/builder/helper/BuildHelper.groovy b/src/main/groovy/de/lisaplus/atlas/builder/helper/BuildHelper.groovy index 7887af7..0adbf14 100644 --- a/src/main/groovy/de/lisaplus/atlas/builder/helper/BuildHelper.groovy +++ b/src/main/groovy/de/lisaplus/atlas/builder/helper/BuildHelper.groovy @@ -13,10 +13,11 @@ class BuildHelper { static String string2Name(String s,boolean firstUpper=true) { def ret = s.replaceAll('[^a-zA-Z0-9]','_') if (firstUpper) { - return ret.substring(0,1).toUpperCase()+ret.substring(1) + return ret.substring(0,1).toUpperCase()+makeCamelCase(ret.substring(1)) + } + else { + return ret.substring(0,1).toLowerCase()+makeCamelCase(ret.substring(1)) } - else - return ret.substring(0,1).toLowerCase()+ret.substring(1) } static String makeCamelCase(String s) { diff --git a/src/main/groovy/de/lisaplus/atlas/codegen/MultiFileGenarator.groovy b/src/main/groovy/de/lisaplus/atlas/codegen/MultiFileGenarator.groovy index f1088b1..739a2e5 100644 --- a/src/main/groovy/de/lisaplus/atlas/codegen/MultiFileGenarator.groovy +++ b/src/main/groovy/de/lisaplus/atlas/codegen/MultiFileGenarator.groovy @@ -32,6 +32,9 @@ abstract class MultiFileGenarator extends GeneratorBase implements ICodeGen { data.extraParam = [:] } + def blackListed=data.extraParam['blackListed'] + def whiteListed=data.extraParam['whiteListed'] + def shouldRemoveEmptyLines = extraParams['removeEmptyLines'] def neededAttrib = extraParams['containsAttrib'] @@ -46,6 +49,16 @@ abstract class MultiFileGenarator extends GeneratorBase implements ICodeGen { return prop.name==missingAttrib } == null : true + boolean handleType=true; + if (whiteListed && (!whiteListed.contains(type.name))) { + handleType = false + println "ingnored by white-list: ${type.name}" + } + else if (blackListed && blackListed.contains(type.name)) { + handleType = false + println "ingnored by black-list: ${type.name}" + } + boolean handleTag = neededTag ? type.tags.find { tag -> return tag==neededTag } != null : true @@ -56,7 +69,7 @@ abstract class MultiFileGenarator extends GeneratorBase implements ICodeGen { } == null } - if (handleNeeded && handleMissing && handleTag) { + if (handleType && handleNeeded && handleMissing && handleTag) { data.put('currentType', type) def ergebnis = template.make(data) def destFileName = getDestFileName(model, extraParams, type) diff --git a/src/test/groovy/de/lisaplus/atlas/Model.groovy b/src/test/groovy/de/lisaplus/atlas/Model.groovy index 33e11ae..a86c404 100644 --- a/src/test/groovy/de/lisaplus/atlas/Model.groovy +++ b/src/test/groovy/de/lisaplus/atlas/Model.groovy @@ -30,7 +30,7 @@ class Model { assertEquals(0,type.refOwner.size()) } assertTrue(found) - typeName='App_module' + typeName='AppModule' found=false model.types.find { it.name==typeName }.each { type -> found=true @@ -52,7 +52,7 @@ class Model { assertEquals(0,type.refOwner.size()) } assertTrue(found) - typeName='User_log' + typeName='UserLog' found=false model.types.find { it.name==typeName }.each { type -> found=true diff --git a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy index 15b0cb8..3126511 100644 --- a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy +++ b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy @@ -52,7 +52,7 @@ class JsonSchemaBuilder { def model = builder.buildModel(modelFile) def timingPlanType = model.types.find { it.name=='TimingPlanType' } assertNotNull(timingPlanType) - def phases_idProp = timingPlanType.properties.find { it.name=='phases_id'} + def phases_idProp = timingPlanType.properties.find { it.name=='phasesId'} assertNotNull(phases_idProp) assertEquals(AggregationType.aggregation,phases_idProp.aggregationType) @@ -75,7 +75,7 @@ class JsonSchemaBuilder { assertTrue(modelFile.isFile()) def builder = new de.lisaplus.atlas.builder.JsonSchemaBuilder() def model = builder.buildModel(modelFile) - def mapObject = model.types.find { it.name=='Map_object' } + def mapObject = model.types.find { it.name=='MapObject' } assertNotNull(mapObject) } @@ -85,7 +85,7 @@ class JsonSchemaBuilder { assertTrue(modelFile.isFile()) def builder = new de.lisaplus.atlas.builder.JsonSchemaBuilder() def model = builder.buildModel(modelFile) - def mapObject = model.types.find { it.name=='GIS_object' } + def mapObject = model.types.find { it.name=='GISObject' } assertNotNull(mapObject) assertEquals(1,mapObject.properties.size()) assertEquals('gis',mapObject.properties[0].name) @@ -97,7 +97,7 @@ class JsonSchemaBuilder { assertTrue(modelFile.isFile()) def builder = new de.lisaplus.atlas.builder.JsonSchemaBuilder() def model = builder.buildModel(modelFile) - def mapObject = model.types.find { it.name=='Map_object' } + def mapObject = model.types.find { it.name=='MapObject' } assertNotNull(mapObject) assertEquals(2,mapObject.properties.size()) assertEquals('gis',mapObject.properties[0].name) @@ -110,7 +110,7 @@ class JsonSchemaBuilder { assertTrue(modelFile.isFile()) def builder = new de.lisaplus.atlas.builder.JsonSchemaBuilder() def model = builder.buildModel(modelFile) - def mapObject = model.types.find { it.name=='Map_object' } + def mapObject = model.types.find { it.name=='MapObject' } assertNotNull(mapObject) assertEquals(2,mapObject.properties.size()) assertEquals('gis',mapObject.properties[0].name) @@ -209,7 +209,7 @@ class JsonSchemaBuilder { it.properties.find { if (it.tags) { propsWithTags++ - assertTrue (it.name.equals('grant') || it.name.equals('module_grants')) + assertTrue (it.name.equals('grant') || it.name.equals('moduleGrants')) } } } diff --git a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/MultiTypeSchema.groovy b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/MultiTypeSchema.groovy index e77f7ef..6b5aadf 100644 --- a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/MultiTypeSchema.groovy +++ b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/MultiTypeSchema.groovy @@ -27,17 +27,17 @@ class MultiTypeSchema { def typeName = 'Action' ModelTestHelper.checkPropertySize(model,typeName,3) ModelTestHelper.compareProperty (new Property( - name: 'default_title', + name: 'defaultTitle', description: 'Tooltip for the main toolbar icon.', type: new StringType() ),model,typeName) ModelTestHelper.compareProperty (new Property( - name: 'default_popup', + name: 'defaultPopup', description: 'The popup appears when the user clicks the icon.', type: new RefType(typeName: 'Icon') ),model,typeName) ModelTestHelper.compareProperty (new Property( - name: 'default_icon', + name: 'defaultIcon', description: 'Icon for the main toolbar.', type: new ComplexType() ),model,typeName) @@ -50,7 +50,7 @@ class MultiTypeSchema { type: new StringType() ),model,typeName) ModelTestHelper.compareProperty (new Property( - name: 'suggested_key', + name: 'suggestedKey', description: null, type: new UnsupportedType() ),model,typeName) diff --git a/src/test/groovy/de/lisaplus/atlas/codegen/test/JavaBeans.groovy b/src/test/groovy/de/lisaplus/atlas/codegen/test/JavaBeans.groovy index 5ebab4b..31bf5c7 100644 --- a/src/test/groovy/de/lisaplus/atlas/codegen/test/JavaBeans.groovy +++ b/src/test/groovy/de/lisaplus/atlas/codegen/test/JavaBeans.groovy @@ -10,6 +10,7 @@ import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals import static org.junit.Assert.assertEquals +import static org.junit.Assert.assertFalse import static org.junit.Assert.assertNotNull import static org.junit.Assert.assertNotNull import static org.junit.Assert.assertTrue @@ -71,7 +72,7 @@ class JavaBeans { doCodeGen.generators.add('java_beans') doCodeGen.outputBaseDir = destDir doCodeGen.generator_parameters.add('removeEmptyLines=true') - doCodeGen.generator_parameters.add('containsAttrib=domain_id') + doCodeGen.generator_parameters.add('containsAttrib=domainId') doCodeGen.generator_parameters.add('packageName=de.test2.jsoncodegen.impl') doCodeGen.run() assertTrue(new File('tmp/java_beans/de/test2/jsoncodegen/impl/Role.java').exists()) @@ -111,4 +112,53 @@ class JavaBeans { } }).size()==5 } + + @Test + void testBlackList() { + def destDir = 'tmp/java_beans_black_list' + FileHelper.removeDirectoryIfExists(destDir) + def modelFile = new File('src/test/resources/test_schemas/ds/user.json') + de.lisaplus.atlas.DoCodeGen doCodeGen = new de.lisaplus.atlas.DoCodeGen() + doCodeGen.model = modelFile + doCodeGen.generators.add('java_beans') + doCodeGen.outputBaseDir = destDir + doCodeGen.generator_parameters.add('removeEmptyLines=true') + doCodeGen.blackListed = ['Domain','Application','App_module','Role'] + doCodeGen.generator_parameters.add('packageName=de.test') + doCodeGen.run() + assertTrue(new File('tmp/java_beans_black_list/de/test/RoleDataGrantsItem.java').exists()) + assertTrue(new File('tmp/java_beans_black_list/de/test/RoleModuleGrantsItem.java').exists()) + assertTrue(new File('tmp/java_beans_black_list/de/test/User.java').exists()) + assertTrue(new File('tmp/java_beans_black_list/de/test/UserLog.java').exists()) + new File('tmp/java_beans_black_list/de/test').listFiles(new FileFilter() { + @Override + boolean accept(File file) { + return file.isFile() + } + }).size()==4 + } + + @Test + void testWhiteList() { + def destDir = 'tmp/java_beans_white_list' + FileHelper.removeDirectoryIfExists(destDir) + def modelFile = new File('src/test/resources/test_schemas/ds/user.json') + de.lisaplus.atlas.DoCodeGen doCodeGen = new de.lisaplus.atlas.DoCodeGen() + doCodeGen.model = modelFile + doCodeGen.generators.add('java_beans') + doCodeGen.outputBaseDir = destDir + doCodeGen.generator_parameters.add('removeEmptyLines=true') + doCodeGen.whiteListed = ['User','Role'] + doCodeGen.generator_parameters.add('packageName=de.test') + doCodeGen.run() + assertTrue(new File('tmp/java_beans_white_list/de/test/Role.java').exists()) + assertTrue(new File('tmp/java_beans_white_list/de/test/User.java').exists()) + new File('tmp/java_beans_white_list/de').listFiles(new FileFilter() { + @Override + boolean accept(File file) { + return file.isFile() + } + }).size()==2 + } + } From 47457b580d6909af6bba7f55beda68daee3e9b45 Mon Sep 17 00:00:00 2001 From: "Thomas, Eiko" Date: Mon, 22 Oct 2018 22:02:09 +0200 Subject: [PATCH 2/4] add test for tag add via -at switch --- .../groovy/de/lisaplus/atlas/DoCodeGen.groovy | 9 ++++- .../test/jsonschema/JsonSchemaBuilder.groovy | 1 - .../atlas/codegen/test/PlantUml.groovy | 40 +++++++++++++++++++ .../resources/test_schemas/ds/incident.json | 12 ++++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy index 41e5d4b..58d9d6b 100644 --- a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy +++ b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy @@ -85,6 +85,11 @@ class DoCodeGen { @Parameter(names = ['-rt', '--remove-tag'], description = "remove a tag from a specific type, f.e. -at User=unused") List typeRemoveTagList = [] + /** + * The datamodel parsed by the builder. It is public accessible for tests + */ + Model dataModel + static void main(String ... args) { DoCodeGen doCodeGen = new DoCodeGen() try { @@ -126,7 +131,7 @@ class DoCodeGen { log.error("unknown file type, currently only jscon schema and xsd are supported: ${model}") System.exit(1) } - Model dataModel = builder.buildModel(modelFile) + dataModel = builder.buildModel(modelFile) adjustTagsForModel(dataModel) // convert extra generator parameter to a map Map extraParameters = getMapFromGeneratorParams(generator_parameters) @@ -367,7 +372,7 @@ class DoCodeGen { } def typeName = typeTagArray[0].trim() def tag = typeTagArray[1].trim() - List alreadyExistingValues = ret.get[typeName] + List alreadyExistingValues = ret[typeName] if (alreadyExistingValues && (!alreadyExistingValues.contains(tag))) { alreadyExistingValues.add(tag) } diff --git a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy index 3126511..8cef4ad 100644 --- a/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy +++ b/src/test/groovy/de/lisaplus/atlas/builder/test/jsonschema/JsonSchemaBuilder.groovy @@ -247,5 +247,4 @@ class JsonSchemaBuilder { assertEquals(2,tagCount) } - } diff --git a/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy b/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy index b556f82..7f07f3f 100644 --- a/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy +++ b/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy @@ -2,7 +2,9 @@ package de.lisaplus.atlas.codegen.test import org.junit.Test +import static junit.framework.Assert.assertEquals import static junit.framework.Assert.assertTrue +import static org.junit.Assert.assertFalse /** * Tests the plantuml generator and template @@ -35,6 +37,44 @@ class PlantUml { assertTrue(new File(destFile).exists()) } + @Test + void createIncidentModelAddTags() { + def destFile = 'tmp/incident.puml' + de.lisaplus.atlas.DoCodeGen doCodeGen = new de.lisaplus.atlas.DoCodeGen() + doCodeGen.model = 'src/test/resources/test_schemas/ds/incident.json' + doCodeGen.generators.add('singlefile=src/main/resources/templates/meta/plantuml.txt') + doCodeGen.outputBaseDir = 'tmp' + doCodeGen.generator_parameters.add('destFileName=incident.puml') + doCodeGen.generator_parameters.add('removeEmptyLines=true') + doCodeGen.typeAddTagList.add('Incident=main') + doCodeGen.typeAddTagList.add('Incident=cool') + doCodeGen.typeAddTagList.add('Domain=cool') + doCodeGen.run() + assertTrue(new File(destFile).exists()) + boolean incidentFound=false + boolean domainFound=false + doCodeGen.dataModel.types.each { type -> + if (type.name=='Incident') { + incidentFound=true + assertEquals(5,type.tags.size()) + assertTrue(type.tags.contains('main')) + assertTrue(type.tags.contains('cool')) + } + else if (type.name=='Domain') { + domainFound=true + assertEquals(1,type.tags.size()) + assertTrue(type.tags.contains('cool')) + } + else { + assertFalse(type.tags.contains('main')) + assertFalse(type.tags.contains('cool')) + } + } + assertTrue(incidentFound) + assertTrue(domainFound) + } + + @Test void createLicenseModel() { def destFile = 'tmp/license.puml' diff --git a/src/test/resources/test_schemas/ds/incident.json b/src/test/resources/test_schemas/ds/incident.json index 3f24ab8..ce6ae12 100644 --- a/src/test/resources/test_schemas/ds/incident.json +++ b/src/test/resources/test_schemas/ds/incident.json @@ -160,6 +160,12 @@ "type": "string", "format": "uuid" }, + "domain_id": { + "description": "what is the related domain", + "type": "string", + "format": "uuid", + "__ref": "./shared/domain.json" + }, "active": { "description": "is this entry still active", "type": "boolean" @@ -201,6 +207,12 @@ }, { "properties": { + "domain_id": { + "description": "what is the related domain", + "type": "string", + "format": "uuid", + "__ref": "./shared/domain.json" + }, "guid": { "description": "object specific ID of that entry", "type": "string", From 7b8a4cb9fc37b6e92f9cce49a1dbe39a3d704925 Mon Sep 17 00:00:00 2001 From: "Thomas, Eiko" Date: Mon, 22 Oct 2018 22:08:22 +0200 Subject: [PATCH 3/4] add test for tag remove via -rt switch --- .../atlas/codegen/test/PlantUml.groovy | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy b/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy index 7f07f3f..e429830 100644 --- a/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy +++ b/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy @@ -74,6 +74,37 @@ class PlantUml { assertTrue(domainFound) } + @Test + void createIncidentModelRemoveTags() { + def destFile = 'tmp/incident.puml' + de.lisaplus.atlas.DoCodeGen doCodeGen = new de.lisaplus.atlas.DoCodeGen() + doCodeGen.model = 'src/test/resources/test_schemas/ds/incident.json' + doCodeGen.generators.add('singlefile=src/main/resources/templates/meta/plantuml.txt') + doCodeGen.outputBaseDir = 'tmp' + doCodeGen.generator_parameters.add('destFileName=incident.puml') + doCodeGen.generator_parameters.add('removeEmptyLines=true') + doCodeGen.typeRemoveTagList.add('Incident=mongodb') + doCodeGen.typeRemoveTagList.add('Incident=rest') + doCodeGen.typeRemoveTagList.add('Incident=joined') + doCodeGen.typeRemoveTagList.add('IncidentTag=rest') + doCodeGen.run() + assertTrue(new File(destFile).exists()) + boolean incidentFound=false + boolean incidentTagFound=false + doCodeGen.dataModel.types.each { type -> + if (type.name=='Incident') { + incidentFound=true + assertEquals(0,type.tags.size()) + } + else if (type.name=='IncidentTag') { + incidentTagFound=true + assertEquals(1,type.tags.size()) + assertTrue(type.tags.contains('mongodb')) + } + } + assertTrue(incidentFound) + assertTrue(incidentTagFound) + } @Test void createLicenseModel() { From b41738f5fcfb42c91fd232fbab45fcaefa080f67 Mon Sep 17 00:00:00 2001 From: "Thomas, Eiko" Date: Tue, 23 Oct 2018 11:22:10 +0200 Subject: [PATCH 4/4] some improvements for plantuml --- Releases.md | 5 ++ .../groovy/de/lisaplus/atlas/DoCodeGen.groovy | 15 +++- src/main/resources/docs/usage.md | 1 + .../resources/templates/meta/plantuml.txt | 81 ++++++++++++++++--- .../templates/meta/plantuml_java.txt | 78 +++++++++++++++--- .../atlas/codegen/test/PlantUml.groovy | 31 +++++++ 6 files changed, 190 insertions(+), 21 deletions(-) diff --git a/Releases.md b/Releases.md index a0e0b3f..13bce63 100644 --- a/Releases.md +++ b/Releases.md @@ -2,7 +2,12 @@ - command line switches for type black- and white-lists - command line switch to add tags to types - command line switch to remove a tag from types +- command line switch to remove a tag from all types - enforce camel-case type names in models +- add guidTypeColor generator parameter for plantuml +- remove printTags generator parameter for plantuml +- add printTypeTags generator parameter for plantuml +- add printPropTags generator parameter for plantuml ## 0.7.5 - deep copy functions for types diff --git a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy index 58d9d6b..e866789 100644 --- a/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy +++ b/src/main/groovy/de/lisaplus/atlas/DoCodeGen.groovy @@ -82,9 +82,15 @@ class DoCodeGen { /** * List of type-name tag-text tuple, after initialization the tags will be removed for the given types in the object tree */ - @Parameter(names = ['-rt', '--remove-tag'], description = "remove a tag from a specific type, f.e. -at User=unused") + @Parameter(names = ['-rt', '--remove-tag'], description = "remove a tag from a specific type, f.e. -rt User=unused") List typeRemoveTagList = [] + /** + * List of tags-text tuple, after initialization the tags will be removed for the given types in the object tree + */ + @Parameter(names = ['-rta', '--remove-tag-all'], description = "remove a tag from all model types, f.e. -rta rest") + List typeRemoveTagAllList = [] + /** * The datamodel parsed by the builder. It is public accessible for tests */ @@ -341,6 +347,12 @@ class DoCodeGen { Map> typeAddTagMap = mapFromConfig(typeAddTagList) Map> typeRemoveTagMap = mapFromConfig(typeRemoveTagList) dataModel.types.each { type -> + // remove all tags + typeRemoveTagAllList.each { tag -> + if (type.tags.contains(tag)) { + type.tags.remove(tag) + } + } // remove undesired tags List tagsToRemove = typeRemoveTagMap[type.name] if (tagsToRemove) { @@ -349,6 +361,7 @@ class DoCodeGen { type.tags.remove(tag) } } + // add new tags List tagsToAdd = typeAddTagMap[type.name] if (tagsToAdd) { // add tags diff --git a/src/main/resources/docs/usage.md b/src/main/resources/docs/usage.md index 48107b0..27967bc 100644 --- a/src/main/resources/docs/usage.md +++ b/src/main/resources/docs/usage.md @@ -95,6 +95,7 @@ build/release/jsonCodeGen.sh -o /tmp/test_beans -m src/test/resources/test_schem ### PlantUML - printTags - if set to true then plantuml prints also tags to the diagrams + - guidTypeColor - if given that color is used as background for the guid-types, f.e. -gp guidTypeColor=adadad ### Base generators * multifiles - creates multiple files from model and extra given template diff --git a/src/main/resources/templates/meta/plantuml.txt b/src/main/resources/templates/meta/plantuml.txt index 2a3c203..0771b5b 100644 --- a/src/main/resources/templates/meta/plantuml.txt +++ b/src/main/resources/templates/meta/plantuml.txt @@ -1,4 +1,9 @@ <% +def printTypeTagsValue = extraParam.printTypeTags=='false' ? false : true +def printPropTagsValue = extraParam.printPropTags=='true' ? true : false +def ignoreUnRefTypes = extraParam.ignoreUnRefTypes=='true' ? true : false + +def guidTypeColor = extraParam.guidTypeColor ? extraParam.guidTypeColor : 'e4ffd4' def printJoins = extraParam.printJoins def printStereoType = { type -> if ( type instanceof de.lisaplus.atlas.model.InnerType ) { @@ -15,12 +20,66 @@ def printStereoType = { type -> } def printPropTags = { prop -> - if (extraParam.printTags==true && prop.tags) { + if (printPropTagsValue && prop.tags) { return "<&tag> ${prop.tags}" } else return '' +} + +def printTypeTags = { type -> + if (printTypeTagsValue && type.tags) { + def s = null + type.tags.each { tag -> + if (s!=null) { + s+=',\\n' + s+=tag + } + else + s=tag + } + return " <${s}>" } + else + return '' +} + + +def typesToIgnore = [] + +extraParam.blackListed.each { typeName -> + typesToIgnore.add(typeName) +} + +if (ignoreUnRefTypes) { + // remove unreferenced type from the diagram + def linkedTypes=[] + + model.types.findAll { type -> + ! typesToIgnore.contains(type.name) + }.each { type -> + type.properties.each { prop -> + def propType + if (prop.isRefTypeOrComplexType()) { + propType = prop.type.type.name + } + else if (prop.implicitRef) { + propType = prop.implicitRef.type.name + } + if (!linkedTypes.contains(propType)) { + linkedTypes.add(propType) + } + } + if (type.refOwner && !linkedTypes.contains(type.name)) { + linkedTypes.add(type.name) + } + } + model.types.each { type -> + if (!linkedTypes.contains(type.name) && !typesToIgnore.contains(type.name)) { + typesToIgnore.add(type.name) + } + } +} %> <% if (extraParam.markdown) { %> @@ -28,6 +87,8 @@ def printPropTags = { prop -> <% } else { %> @startuml <% } %> +skinparam roundcorner 10 + skinparam class { BackgroundColor #FFFFFF ArrowColor #000000 @@ -36,7 +97,7 @@ skinparam class { BorderColor<> #777777 BackgroundColor<> #EEEEEE - BackgroundColor<> #e4ffd4 + BackgroundColor<> #${guidTypeColor} FontName Courier FontSize 12 @@ -54,8 +115,10 @@ skinparam classAttribute { FontSize 12 } -<% model.types.each { type -> %> -class ${firstUpperCase.call(type.name)} ${ printStereoType(type) } << ( ,${type.color}) >> { +<% model.types.findAll { type -> + ! typesToIgnore.contains(type.name) +}.each { type -> %> +class ${firstUpperCase.call(type.name)} ${printTypeTags(type) }${ printStereoType(type) } << ( ,${type.color}) >> { <% def i=0; type.properties.each { prop -> def arrayStr = prop.type.isArray ? '[]' : '' i++ @@ -70,19 +133,17 @@ class ${firstUpperCase.call(type.name)} ${ printStereoType(type) } << ( ,${typ <% } %> <% } %> } - <% if (type.description || (extraParam.printTags==true && type.tags)) { %> + <% if (type.description) { %> note top of ${firstUpperCase.call(type.name)} ${breakTxt.call(type.description,10)} - <% if (extraParam.printTags==true && type.tags) { %> -.. -<&tag> //${type.tags}// - <% } %> end note <% } %> <% } %> hide methods -<% model.types.each { type -> %> +<% model.types.findAll { type -> + ! typesToIgnore.contains(type.name) +}.each { type -> %> <% def linkedTypes=[] %> <% type.properties.each { prop -> %> <% if (prop.isRefTypeOrComplexType()) { %> diff --git a/src/main/resources/templates/meta/plantuml_java.txt b/src/main/resources/templates/meta/plantuml_java.txt index 502c0ff..269143d 100644 --- a/src/main/resources/templates/meta/plantuml_java.txt +++ b/src/main/resources/templates/meta/plantuml_java.txt @@ -1,4 +1,9 @@ <% +def printTypeTagsValue = extraParam.printTypeTags=='false' ? false : true +def printPropTagsValue = extraParam.printPropTags=='true' ? true : false +def ignoreUnRefTypes = extraParam.ignoreUnRefTypes=='false' ? false : true + +def guidTypeColor = extraParam.guidTypeColor ? extraParam.guidTypeColor : 'e4ffd4' def printJoins = extraParam.printJoins def printStereoType = { type -> if ( type instanceof de.lisaplus.atlas.model.InnerType ) { @@ -15,12 +20,65 @@ def printStereoType = { type -> } def printPropTags = { prop -> - if (extraParam.printTags==true && prop.tags) { + if (printPropTagsValue && prop.tags) { return "<&tag> ${prop.tags}" } else return '' } + +def printTypeTags = { type -> + if (printTypeTagsValue && type.tags) { + def s = null + type.tags.each { tag -> + if (s!=null) { + s+=',\\n' + s+=tag + } + else + s=tag + } + return " <${s}>" + } + else + return '' +} + +def typesToIgnore = [] + +extraParam.blackListed.each { typeName -> + typesToIgnore.add(typeName) +} + +if (ignoreUnRefTypes) { + // remove unreferenced type from the diagram + def linkedTypes=[] + model.types.findAll { type -> + ! typesToIgnore.contains(type.name) + }.each { type -> + type.properties.each { prop -> + def propType + if (prop.isRefTypeOrComplexType()) { + propType = prop.type.type.name + } + else if (prop.implicitRef) { + propType = prop.implicitRef.type.name + } + if (!linkedTypes.contains(propType)) { + linkedTypes.add(propType) + } + } + if (type.refOwner && !linkedTypes.contains(type.name)) { + linkedTypes.add(type.name) + } + } + model.types.each { type -> + if (!linkedType.contains(type.name) && !typesToIgnore.contains(type.name)) { + typesToIgnore.add(type.name) + } + } +} + %> <% if (extraParam.markdown) { %> ```plantuml @@ -35,7 +93,7 @@ skinparam class { BorderColor<> #777777 BackgroundColor<> #EEEEEE - BackgroundColor<> #e4ffd4 + BackgroundColor<> #${guidTypeColor} FontName Courier FontSize 12 @@ -53,8 +111,10 @@ skinparam classAttribute { FontSize 12 } -<% model.types.each { type -> %> -class ${firstUpperCase.call(type.name)} ${ printStereoType(type) } << ( ,${type.color}) >> { +<% model.types.findAll { type -> + ! typesToIgnore.contains(type.name) +}.each { type -> %> +class ${firstUpperCase.call(type.name)} ${printTypeTags(type) }${ printStereoType(type) } << ( ,${type.color}) >> { <% def i=0; type.properties.each { prop -> def arrayStr = prop.type.isArray ? '[]' : '' i++ @@ -68,19 +128,17 @@ class ${firstUpperCase.call(type.name)} ${ printStereoType(type) } << ( ,${typ <% } %> <% } %> } - <% if (type.description || (extraParam.printTags==true && type.tags)) { %> + <% if (type.description) { %> note top of ${firstUpperCase.call(type.name)} ${breakTxt.call(type.description,10)} - <% if (extraParam.printTags==true && type.tags) { %> -.. -<&tag> //${type.tags}// - <% } %> end note <% } %> <% } %> hide methods -<% model.types.each { type -> %> +<% model.types.findAll { type -> + ! typesToIgnore.contains(type.name) +}.each { type -> %> <% def linkedTypes=[] %> <% type.properties.each { prop -> %> <% if (prop.isRefTypeOrComplexType()) { %> diff --git a/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy b/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy index e429830..cbfe8c0 100644 --- a/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy +++ b/src/test/groovy/de/lisaplus/atlas/codegen/test/PlantUml.groovy @@ -106,6 +106,37 @@ class PlantUml { assertTrue(incidentTagFound) } + @Test + void createIncidentModelRemoveAllTags() { + def destFile = 'tmp/incident.puml' + de.lisaplus.atlas.DoCodeGen doCodeGen = new de.lisaplus.atlas.DoCodeGen() + doCodeGen.model = 'src/test/resources/test_schemas/ds/incident.json' + doCodeGen.generators.add('singlefile=src/main/resources/templates/meta/plantuml.txt') + doCodeGen.outputBaseDir = 'tmp' + doCodeGen.generator_parameters.add('destFileName=incident.puml') + doCodeGen.generator_parameters.add('removeEmptyLines=true') + doCodeGen.generator_parameters.add('guidTypeColor=f9f6e0') + doCodeGen.generator_parameters.add('ignoreUnRefTypes=true') + doCodeGen.typeRemoveTagAllList.add('rest') + doCodeGen.run() + assertTrue(new File(destFile).exists()) + boolean incidentFound=false + boolean incidentTagFound=false + doCodeGen.dataModel.types.each { type -> + assertFalse(type.tags.contains('rest')) + if (type.name=='Incident') { + incidentFound=true + assertEquals(2,type.tags.size()) + } + else if (type.name=='IncidentTag') { + incidentTagFound=true + assertEquals(1,type.tags.size()) + } + } + assertTrue(incidentFound) + assertTrue(incidentTagFound) + } + @Test void createLicenseModel() { def destFile = 'tmp/license.puml'