Commit 3fe3a5bc authored by René Schöne's avatar René Schöne
Browse files

Merge branch 'release' into 'master'

0.3.6

See merge request jastadd/relast2uml!6
parents 45b09e3f c35fbad7
Pipeline #12750 passed with stages
in 3 minutes and 11 seconds
......@@ -6,3 +6,4 @@
.idea/
.gradle/
/build/
/public/
......@@ -4,6 +4,7 @@ variables:
stages:
- build
- test
- ragdoc
- publish
build:
......@@ -12,33 +13,86 @@ build:
before_script:
- ls -lah *
script:
- ./gradlew assemble
- "./gradlew assemble"
test:
image: openjdk:11
stage: test
needs:
- build
script:
- ./gradlew test
- "./gradlew test"
artifacts:
reports:
junit: relast2uml.tests/build/test-results/test/TEST-*.xml
junit: "*/build/test-results/test/TEST-*.xml"
publish:
publish_dev:
image: openjdk:11
stage: publish
needs:
- test
script:
- "./gradlew setDevVersionForCI"
- "./gradlew publish"
only:
- dev
publish_master:
image: openjdk:11
stage: publish
needs:
- test
script:
- "./gradlew publish"
only:
- master
ragdoc_build:
image:
name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-builder"
entrypoint: [""]
stage: ragdoc
needs:
- build
script:
- JAVA_FILES=$(find dumpAstWithPlantuml/src/ -name '*.java')
- /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES
artifacts:
paths:
- "data/"
ragdoc_view:
image:
name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-view:relations"
entrypoint: [""]
stage: ragdoc
needs:
- ragdoc_build
script:
- DATA_DIR=$(pwd -P)/data
- mkdir -p pages/docs/ragdoc
- OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc
- cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR
- /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR
only:
- dev
- main
artifacts:
paths:
- "pages/docs/ragdoc"
pages:
image: python:3.7-alpine
image: python:3.10.0-bullseye
stage: publish
needs:
- ragdoc_view
- test
before_script:
- pip install -r pages/requirements.txt
script:
- pip install -U sphinx sphinx-rtd-theme recommonmark sphinxemoji sphinx-markdown-tables
- sphinx-build -b html pages/ public
- cd pages && mkdocs build
artifacts:
paths:
- public
- public/
only:
- master
- main
......@@ -46,6 +46,14 @@ task newVersion() {
}
}
task setDevVersionForCI() {
doFirst {
def props = new Properties()
props['version'] = version + "-$System.env.CI_PIPELINE_IID"
props.store(file(versionFile).newWriter(), null)
}
}
//679
publishing {
publications {
......
DumpAst ::= DumpNode* <PackageName> BuildConfig PrintConfig ;
rel DumpAst.RootNode -> DumpNode ;
BuildConfig ::= GlobalPatternCollection:PatternCollection ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping* <TypeIgnorePattern> <IncludeEmptyString:boolean> <Debug:boolean> ;
BuildConfig ::= StyleInformation GlobalPatternCollection:PatternCollection
ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping*
<TypeIgnorePattern> <IncludeEmptyString:boolean> <ExcludeNullNodes:boolean> <Debug:boolean>;
TypePatternCollectionMapping ::= <TypeRegex> PatternCollection ;
PatternCollection ::= <TokenPattern> <ChildPattern> <RelationPattern> <AttributePattern> <NonterminalAttributePattern> ;
PrintConfig ::= <Scale:double> <Version> Header* ;
StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod> <TextColorMethod:StyleMethod>;
PrintConfig ::= <Scale:double> <Version> <OrderChildren:boolean> Header* ;
Header ::= <Value> ;
DumpNode ::= <Name> <Label> <Object:Object> <Invisible:boolean> DumpChildNode* DumpToken* DumpRelation* /InvisiblePath/ ;
DumpNode ::= DumpChildNode* DumpToken* DumpRelation*
<Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean>
/InvisiblePath/ ;
InnerDumpNode ;
rel InnerDumpNode.DumpNode -> DumpNode ;
rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner ;
abstract DumpChildNode ::= <Name> <Computed:boolean> ;
DumpNormalChildNode : DumpChildNode ;
rel DumpNormalChildNode.DumpNode -> DumpNode ;
rel DumpNormalChildNode.DumpNode <-> DumpNode.ContainerOfNormalChild ;
DumpListChildNode : DumpChildNode ::= InnerDumpNode* ;
abstract DumpToken ::= <Name> <Computed:boolean> ;
......
......@@ -26,11 +26,23 @@ aspect GenerationBackend {
}
protected DumpNode DumpAst.transform(TransformationTransferInformation tti, Object obj, Source source)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (obj == null) {
return transform(tti, obj, source, false);
}
protected DumpNode DumpAst.transform(
TransformationTransferInformation tti, Object obj, Source source, boolean allowNullObj)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (obj == null && !allowNullObj) {
return null;
}
DumpNode node = tti.transformed.get(obj);
String objClassName = obj.getClass().getSimpleName();
DumpNode node;
String objClassName;
if (obj == null) {
node = null;
objClassName = "null";
} else {
node = tti.transformed.get(obj);
objClassName = obj.getClass().getSimpleName();
}
if (node != null) {
if (source == Source.RELATION) {
return node;
......@@ -40,106 +52,118 @@ aspect GenerationBackend {
} else {
node = new DumpNode();
node.setObject(obj);
node.setLabel(objClassName + "@" + obj.hashCode());
node.setName("node" + tti.transformed.size());
tti.transformed.put(obj, node);
this.addDumpNode(node);
}
if (node.isAstNode()) {
// do not process node further if coming from a relation
if (source == Source.RELATION) {
tti.relationTargetsUnprocessed.put(node, true);
return node;
}
if (source == Source.INVISIBLE_PARENT || !isTypeEnabled(objClassName)) {
node.setInvisible(true);
if (!node.isAstNode()) {
return node;
}
applyStyle(node);
// do not process node further if coming from a relation
if (source == Source.RELATION) {
tti.relationTargetsUnprocessed.put(node, true);
return node;
}
if (source == Source.INVISIBLE_PARENT || !isTypeEnabled(objClassName)) {
node.setInvisible(true);
}
if (obj == null) {
// for a null object, we do not need any further analysis
return node;
}
final ClassAnalysisResult car = analyzeClass(obj.getClass());
// -- singleChild --
for (SingleChildMethod singleChildMethod : car.singleChildMethods()) {
Object target = singleChildMethod.getMethod().invoke(obj);
String childName = singleChildMethod.getName();
DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)), !getBuildConfig().getExcludeNullNodes());
if (targetNode != null) {
DumpNormalChildNode normalChild = new DumpNormalChildNode();
normalChild.setName(childName);
normalChild.setDumpNode(targetNode);
normalChild.setComputed(singleChildMethod.isNTASingleChildMethod());
node.addDumpChildNode(normalChild);
}
final ClassAnalysisResult car = analyzeClass(obj.getClass());
// -- singleChild --
for (SingleChildMethod singleChildMethod : car.singleChildMethods()) {
Object target = singleChildMethod.getMethod().invoke(obj);
String childName = singleChildMethod.getName();
DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)));
}
// -- listChild --
for (ListChildMethod listChildMethod : car.listChildMethods()) {
Iterable<?> targetList = (Iterable<?>) listChildMethod.getMethod().invoke(obj);
DumpListChildNode listChild = new DumpListChildNode();
listChild.setComputed(listChildMethod.isNTAListChildMethod());
String childName = listChildMethod.getName();
boolean shouldBeInvisisble = !isChildEnabled(objClassName, childName);
listChild.setName(childName);
for (Object target : targetList) {
DumpNode targetNode = transform(tti, target, nextSource(source, shouldBeInvisisble));
if (target != null && targetNode != null) {
DumpNormalChildNode normalChild = new DumpNormalChildNode();
normalChild.setName(childName);
normalChild.setDumpNode(targetNode);
normalChild.setComputed(singleChildMethod.isNTASingleChildMethod());
node.addDumpChildNode(normalChild);
listChild.addInnerDumpNode(new InnerDumpNode(targetNode));
}
}
// -- listChild --
for (ListChildMethod listChildMethod : car.listChildMethods()) {
Iterable<?> targetList = (Iterable<?>) listChildMethod.getMethod().invoke(obj);
DumpListChildNode listChild = new DumpListChildNode();
listChild.setComputed(listChildMethod.isNTAListChildMethod());
String childName = listChildMethod.getName();
boolean shouldBeInvisisble = !isChildEnabled(objClassName, childName);
listChild.setName(childName);
for (Object target : targetList) {
DumpNode targetNode = transform(tti, target, nextSource(source, shouldBeInvisisble));
if (target != null && targetNode != null) {
listChild.addInnerDumpNode(new InnerDumpNode(targetNode));
}
}
if (listChild.getNumInnerDumpNode() > 0) {
node.addDumpChildNode(listChild);
}
if (listChild.getNumInnerDumpNode() > 0) {
node.addDumpChildNode(listChild);
}
}
// -- singleRelation --
for (SingleRelationMethod singleRelationMethod : car.singleRelationMethods()) {
Object target = singleRelationMethod.getMethod().invoke(obj);
DumpNode targetNode = transform(tti, target, Source.RELATION);
if (target != null && targetNode != null) {
DumpNormalRelation normalRelation = new DumpNormalRelation();
normalRelation.setName(singleRelationMethod.getName());
normalRelation.setDumpNode(targetNode);
node.addDumpRelation(normalRelation);
}
// -- singleRelation --
for (SingleRelationMethod singleRelationMethod : car.singleRelationMethods()) {
Object target = singleRelationMethod.getMethod().invoke(obj);
}
// -- listRelation --
for (ListRelationMethod listRelationMethod : car.listRelationMethods()) {
Iterable<?> targetList = (Iterable<?>) listRelationMethod.getMethod().invoke(obj);
DumpListRelation listRelation = new DumpListRelation();
listRelation.setName(listRelationMethod.getName());
for (Object target : targetList) {
DumpNode targetNode = transform(tti, target, Source.RELATION);
if (target != null && targetNode != null) {
DumpNormalRelation normalRelation = new DumpNormalRelation();
normalRelation.setName(singleRelationMethod.getName());
normalRelation.setDumpNode(targetNode);
node.addDumpRelation(normalRelation);
listRelation.addInnerDumpNode(new InnerDumpNode(targetNode));
}
}
// -- listRelation --
for (ListRelationMethod listRelationMethod : car.listRelationMethods()) {
Iterable<?> targetList = (Iterable<?>) listRelationMethod.getMethod().invoke(obj);
DumpListRelation listRelation = new DumpListRelation();
listRelation.setName(listRelationMethod.getName());
for (Object target : targetList) {
DumpNode targetNode = transform(tti, target, Source.RELATION);
if (target != null && targetNode != null) {
listRelation.addInnerDumpNode(new InnerDumpNode(targetNode));
}
}
if (listRelation.getNumInnerDumpNode() > 0) {
node.addDumpRelation(listRelation);
}
if (listRelation.getNumInnerDumpNode() > 0) {
node.addDumpRelation(listRelation);
}
// -- token --
for (TokenMethod tokenMethod : car.tokenMethods()) {
Object target = tokenMethod.getMethod().invoke(obj);
if (target != null) {
DumpNode targetNode = transform(tti, target, Source.RELATION);
DumpToken token = null;
// TODO check, if Iterable.isAssignableFrom(target.getClass()).
// if so, check isAstNode for first non-null to add DumpReferenceToken's, otherwise DumpValueToken's
if (targetNode != null && targetNode.isAstNode()) {
token = new DumpReferenceToken().setValue(targetNode);
} else {
if (target != null && (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty())) {
DumpValueToken valueToken = new DumpValueToken();
valueToken.setValue(target);
token = valueToken;
}
}
if (token != null) {
token.setName(tokenMethod.getName());
token.setComputed(tokenMethod.isAttributeMethod());
node.addDumpToken(token);
}
// -- token --
for (TokenMethod tokenMethod : car.tokenMethods()) {
Object target = tokenMethod.getMethod().invoke(obj);
if (target != null) {
DumpNode targetNode = transform(tti, target, Source.RELATION);
DumpToken token = null;
// TODO check, if Iterable.isAssignableFrom(target.getClass()).
// if so, check isAstNode for first non-null to add DumpReferenceToken's, otherwise DumpValueToken's
if (targetNode != null && targetNode.isAstNode()) {
token = new DumpReferenceToken().setValue(targetNode);
} else {
if (target != null && (getBuildConfig().getIncludeEmptyString() || !target.toString().isEmpty())) {
DumpValueToken valueToken = new DumpValueToken();
valueToken.setValue(target);
token = valueToken;
}
}
if (token != null) {
token.setName(tokenMethod.getName());
token.setComputed(tokenMethod.isAttributeMethod());
node.addDumpToken(token);
}
}
}
return node;
}
private void DumpAst.applyStyle(DumpNode node) {
Object obj = node.getObject();
node.setLabel(getBuildConfig().getStyleInformation().getNameMethod().get(obj));
node.setBackgroundColor(getBuildConfig().getStyleInformation().getBackgroundColorMethod().get(obj));
node.setTextColor(getBuildConfig().getStyleInformation().getTextColorMethod().get(obj));
}
private Source DumpAst.nextSource(Source currentSource, boolean shouldBeInvisible) {
return currentSource == Source.INVISIBLE_PARENT ? Source.INVISIBLE_PARENT :
(shouldBeInvisible ? Source.INVISIBLE_PARENT : Source.PARENT);
......@@ -412,6 +436,10 @@ aspect GenerationBackend {
// --- isAstNode ---
syn boolean DumpNode.isAstNode() {
if (getObject() == null) {
// this is only possible for normal child nodes, and they are ast nodes
return true;
}
Class<?> clazz = getObject().getClass();
for (java.lang.reflect.Method method : clazz.getMethods()) {
if ("init$Children".equals(method.getName()) && method.getParameterCount() == 0) {
......@@ -450,33 +478,47 @@ aspect GenerationBackend {
return result;
}
class TransformationTransferInformation {
java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>();
java.util.Map<DumpNode, Boolean> relationTargetsUnprocessed = new java.util.HashMap<>();
// --- labelAndTextColor ---
syn String DumpNode.labelAndTextColor() {
if (getTextColor().isEmpty()) {
return getLabel();
} else {
return "<color:" + getTextColor() + ">" + getLabel() + "</color>";
}
}
syn String DumpAst.toPlantUml() {
StringBuilder sb = new StringBuilder();
com.github.mustachejava.reflect.ReflectionObjectHandler roh = new com.github.mustachejava.reflect.ReflectionObjectHandler() {
@Override
public com.github.mustachejava.Binding createBinding(String name, final com.github.mustachejava.TemplateContext tc, com.github.mustachejava.Code code) {
return new com.github.mustachejava.reflect.GuardedBinding(this, name, tc, code) {
@Override
protected synchronized com.github.mustachejava.util.Wrapper getWrapper(String name, java.util.List<Object> scopes) {
com.github.mustachejava.util.Wrapper wrapper = super.getWrapper(name, scopes);
if (wrapper instanceof com.github.mustachejava.reflect.MissingWrapper) {
throw new com.github.mustachejava.MustacheException(name + " not found in " + tc);
}
return wrapper;
}
};
// --- myChildren ---
syn java.util.List<DumpNode> DumpNode.myChildren() {
java.util.List<DumpNode> result = new java.util.ArrayList<>();
for (DumpChildNode childNode : getDumpChildNodeList()) {
for (DumpNode inner : childNode.innerNodes(true)) {
result.add(inner);
}
};
com.github.mustachejava.DefaultMustacheFactory mf = new com.github.mustachejava.DefaultMustacheFactory();
mf.setObjectHandler(roh);
com.github.mustachejava.Mustache m = mf.compile("dumpAst.mustache");
m.execute(new java.io.PrintWriter(new AppendableWriter(sb)), this);
return sb.toString();
}
return result;
}
// --- successor ---
syn DumpNode DumpNode.successor() {
if (container() == null) {
// not contained
return null;
}
java.util.List<DumpNode> siblingsAndMe = container().myChildren();
int indexOfMe = siblingsAndMe.indexOf(this);
if (indexOfMe == siblingsAndMe.size() - 1) {
// last child
return null;
}
return siblingsAndMe.get(indexOfMe + 1);
}
// --- hasSuccessor ---
syn boolean DumpNode.hasSuccessor() = successor() != null;
class TransformationTransferInformation {
java.util.Map<Object, DumpNode> transformed = new java.util.HashMap<>();
java.util.Map<DumpNode, Boolean> relationTargetsUnprocessed = new java.util.HashMap<>();
}
syn String DumpAst.toYaml(boolean prependCreationComment) {
......@@ -558,4 +600,17 @@ aspect GenerationBackend {
public void close() {
}
}
static StyleInformation StyleInformation.createDefault() {
StyleInformation result = new StyleInformation();
result.setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode()));
result.setBackgroundColorMethod(n -> "");
result.setTextColorMethod(n -> "");
return result;
}
@FunctionalInterface
public interface StyleMethod<ASTNODE> {
String get(ASTNODE node);
}
}
......@@ -62,6 +62,7 @@ public class DumpBuilder {
this.target = target;
buildConfig = new BuildConfig();
buildConfig.setGlobalPatternCollection(new PatternCollection());
buildConfig.setStyleInformation(StyleInformation.createDefault());
printConfig = new PrintConfig();
printConfig.setScale(1);
printConfig.setVersion(readVersion());
......@@ -307,6 +308,16 @@ public class DumpBuilder {
}
}
public DumpBuilder excludeNullNodes() {
buildConfig.setExcludeNullNodes(true);
return this;
}
public DumpBuilder includeNullNodes() {
buildConfig.setExcludeNullNodes(false);
return this;
}
public DumpBuilder customPreamble(String option) {
printConfig.addHeader(new Header(option));
return this;
......@@ -321,11 +332,31 @@ public class DumpBuilder {
return this;
}
public <ASTNODE> DumpBuilder setNameMethod(StyleMethod<ASTNODE> nameMethod) {
buildConfig.getStyleInformation().setNameMethod(nameMethod);
return this;
}
public <ASTNODE> DumpBuilder setBackgroundColorMethod(StyleMethod<ASTNODE> colorMethod) {
buildConfig.getStyleInformation().setBackgroundColorMethod(colorMethod);
return this;
}
public <ASTNODE> DumpBuilder setTextColorMethod(StyleMethod<ASTNODE> colorMethod) {
buildConfig.getStyleInformation().setTextColorMethod(colorMethod);
return this;
}
public DumpBuilder setScale(double value) {
printConfig.setScale(value);
return this;
}
public DumpBuilder orderChildren() {
printConfig.setOrderChildren(true);
return this;
}
private String readVersion() {
try {
java.util.ResourceBundle resources = java.util.ResourceBundle.getBundle("dumpAstVersion");
......
aspect GenerationMustache {
syn String DumpAst.toPlantUml() {
StringBuilder sb = new StringBuilder();
com.github.mustachejava.reflect.ReflectionObjectHandler roh = new com.github.mustachejava.reflect.ReflectionObjectHandler() {
@Override
public com.github.mustachejava.Binding createBinding(String name, final com.github.mustachejava.TemplateContext tc, com.github.mustachejava.Code code) {
return new com.github.mustachejava.reflect.GuardedBinding(this, name, tc, code) {
@Override
protected synchronized com.github.mustachejava.util.Wrapper getWrapper(String name, java.util.List<Object> scopes) {
com.github.mustachejava.util.Wrapper wrapper = super.getWrapper(name, scopes);
if (wrapper instanceof com.github.mustachejava.reflect.MissingWrapper) {
throw new com.github.mustachejava.MustacheException(name + " not found in " + tc);
}
return wrapper;
}
};
}
};
com.github.mustachejava.DefaultMustacheFactory mf = new com.github.mustachejava.DefaultMustacheFactory();
mf.setObjectHandler(roh);
com.github.mustachejava.Mustache m = mf.compile("dumpAst.mustache");
m.execute(new java.io.PrintWriter(new AppendableWriter(sb)), this);
return sb.toString();
}
}
......@@ -33,6 +33,17 @@ aspect Navigation {
eq DumpNode.getDumpRelation().containingDumpNode() = this;
eq DumpNode.getInvisiblePath().containingDumpNode() = this;
// --- container ---
syn DumpNode DumpNode.container() {
if (getContainerOfNormalChild() != null) {
return getContainerOfNormalChild().containingDumpNode();
}
if (getContainerOfInner() != null) {
return getContainerOfInner().containingDumpNode();
}
return null;
}
// --- innerVisibleNodes ---
syn java.util.List<DumpNode> DumpChildNode.innerVisibleNodes() = innerNodes(true);
syn java.util.List<DumpNode> DumpRelation.innerVisibleNodes() = innerNodes(true);
......
......@@ -9,7 +9,7 @@ scale {{Scale}}
{{#DumpNodes}}
{{#isAstNode}}
{{^Invisible}}
object "{{label}}" as {{name}} {
object "{{{labelAndTextColor}}}" as {{name}} {{#backgroundColor}}#{{{backgroundColor}}}{{/backgroundColor}} {
{{#DumpTokens}}
{{#isDumpValueToken}}
{{label}} = {{{Value}}}
......@@ -63,6 +63,13 @@ object "{{label}}" as {{name}} {
{{/InnerDumpNodes}}
{{/InvisiblePath}}
{{/Invisible}}
{{#PrintConfig}}{{#orderChildren}}
{{#myChildren}}
{{#hasSuccessor}}
{{name}} -[hidden]right-> {{#successor}}{{name}}{{/successor}}
{{/hasSuccessor}}
{{/myChildren}}
{{/orderChildren}}{{/PrintConfig}}
{{/DumpNodes}}
{{#BuildConfig}}
{{#Debug}}
......
#Fri Jan 15 20:29:48 CET 2021
version=0.3.5
#Thu Feb 24 09:45:15 CET 2022
version=0.3.6
build
src/gen-res/
src/gen/
out/
*.class
buildscript {
repositories.mavenLocal()
repositories.mavenCentral()
dependencies {
classpath group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.3'
}
}