Browse Source

New scope of repo: all drawio -> OML conversions

Joeri Exelmans 2 years ago
parent
commit
239162578c

+ 2 - 2
default.nix

@@ -1,8 +1,8 @@
 {
   pkgs ? import <nixpkgs> {},
   drawio2py ? import (builtins.fetchGit {
-    url = "git@msdl.uantwerpen.be:rparedis/DrawioConvert.git";
-    rev = "7265d662de0c899e968fc8ca8173d7aba4194f7a";
+    url = "git@msdl.uantwerpen.be:jexelmans/drawio2py.git";
+    rev = "a7191df40e10b1c8d74e651b50bb4d81c2eafd74";
     ref = "library";
   }) {}
 }:

+ 20 - 0
drawio2oml/drawio/drawio2oml.py

@@ -0,0 +1,20 @@
+import argparse
+import sys
+
+from drawio2oml.drawio import parser, abstract_syntax, oml_generator
+
+if __name__ == "__main__":
+    argparser = argparse.ArgumentParser(
+        description = "Converts Draw.io files to OML.")
+    argparser.add_argument('inputfile')
+    argparser.add_argument('-o', '--output', metavar='FILE', nargs=1, help="OML output file. If not specified, output will be printed to stdout.")
+    args = argparser.parse_args() # exits on error
+
+    asyntax = parser.Parser.parse(args.inputfile)
+
+    if args.output == None:
+        
+        oml_generator.write_oml(asyntax, sys.stdout)
+    else:
+        with open(args.output[0], 'wt') as f:
+            oml_generator.write_oml(asyntax, f)

+ 47 - 0
drawio2oml/drawio/oml_generator.py

@@ -0,0 +1,47 @@
+import io
+import os
+import typing
+
+import jinja2
+
+from drawio2py import abstract_syntax
+from drawio2oml import util
+
+def assign_names(drawio_file: abstract_syntax.DrawIOFile) -> typing.Dict[abstract_syntax.Element, str]:
+    names = {}
+    for page_idx, page in enumerate(drawio_file.pages):
+        names[page] = "p"+str(page_idx)
+        def visit_cell(cell):
+            names[cell.id] = "p"+str(page_idx)+"_cell_"+str(cell.id)
+            for child in cell.children:
+                visit_cell(child)
+        visit_cell(page.root)
+    return names
+
+
+def write_oml(
+    drawio_file: abstract_syntax.DrawIOFile,
+    drawio_names: typing.Dict[abstract_syntax.Element, str],
+    ostream: io.TextIOBase,
+    output_namespace: str = "http://ua.be/sdo2l/description/artifacts/my_drawio",
+    namespaces=util.DTDESIGN_NAMESPACES):
+    """
+    Generate an OML description of a drawio diagram.
+    Parameters:
+        drawio_file: abstract syntax of the drawio file
+        drawio_names: mapping from every element in the drawio file to a unique name
+        ostream: stream to write OML output to (e.g., stdout, a file, ...)
+        output_namespace: namespace for the to-be-generated OML description
+        namespaces: namespaces of vocabularies to use
+    """
+
+    environment = jinja2.Environment(
+        loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
+    environment.filters['to_oml_string_literal'] = util.to_oml_string_literal
+    template = environment.get_template("oml_template.j2")
+
+    for piece in template.generate(
+            file=drawio_file,
+            enumerate=enumerate,
+            namespaces=namespaces):
+        ostream.write(piece)

+ 127 - 0
drawio2oml/drawio/oml_template.j2

@@ -0,0 +1,127 @@
+// Warning: Generated code! Do not edit!
+// Input file: '{{file.filename}}'
+// Generator: https://msdl.uantwerpen.be/git/rparedis/DrawioConvert/src/library
+
+{%- macro point(p) -%}
+drawio:hasX {{p.x}}
+drawio:hasY {{p.y}}
+{%- endmacro -%}
+
+{%- macro write_cell(page_index, cell) %}
+  {%- set cell_iri = "p"+(page_index|string)+"_cell_"+(cell.id|string) -%}
+  ci {{cell_iri}} : drawio:{{cell.__class__.__name__}} [
+    drawio:hasDrawioId {{cell.id|to_oml_string_literal}}
+    {%- if cell.value != "" %}
+    drawio:hasValue {{cell.value|to_oml_string_literal}}
+    {%- endif %}
+    {%- if cell.parent != None %}
+    drawio:hasParent p{{page_index}}_cell_{{cell.parent.id}}
+    {%- else %}
+    drawio:isRootOf p{{page_index}}
+    {%- endif %}
+    object_diagram:inModel model
+
+    {%- if cell.__class__.__name__ == "Vertex" %}
+    drawio:hasVertexGeometry drawio:VertexGeometry [
+      {{ point(cell.geometry)|indent(6) }}
+      drawio:hasWidth {{cell.geometry.width}}
+      drawio:hasHeight {{cell.geometry.height}}
+    ]
+    {% endif -%}
+
+    {%- if cell.__class__.__name__ == "Edge" %}
+    drawio:hasEdgeGeometry drawio:EdgeGeometry [
+      {%- for p in cell.geometry.points -%}
+      drawio:hasPoint drawio:PointListItem [
+        drawio:hasListIndex {{loop.index0}}
+        {{ point(p)|indent(8) }}
+      ]
+      {%- endfor %}
+      {%- if cell.geometry.source_point != None %}
+      drawio:hasSourcePoint drawio:Point [
+        {{ point(cell.geometry.source_point)|indent(8) }}
+      ]
+      {%- endif %}
+      {%- if cell.geometry.target_point != None %}
+      drawio:hasTargetPoint drawio:Point [
+        {{ point(cell.geometry.target_point)|indent(8) }}
+      ]
+      {%- endif %}
+    ]
+    {%- if cell.source %}
+    drawio:hasSource p{{page_index}}_cell_{{cell.source.id}}
+    {%- endif -%}
+    {%- if cell.target %}
+    drawio:hasTarget p{{page_index}}_cell_{{cell.target.id}}
+    {%- endif -%}
+    {%- endif %}
+  ]
+  {# Cell properties #}
+  {%-for prop_key,prop_val in cell.properties.items() %}
+  ci {{cell_iri}}_prop_{{prop_key}} : drawio:CellProperty [
+    dict:hasKey {{prop_key|to_oml_string_literal}}
+    dict:hasValue {{prop_val|to_oml_string_literal}}
+    drawio:propertyOf {{cell_iri}}
+    object_diagram:inModel model
+  ]
+  {%- endfor %}
+  {# Cell style #}
+  {%- for style_key,style_val in cell.style.data.items() %}
+  ci {{cell_iri}}_sty_{{style_key}} : drawio:CellStyleEntry [
+    dict:hasKey {{style_key|to_oml_string_literal}}
+    dict:hasValue {{style_val|to_oml_string_literal}}
+    drawio:styleEntryOf {{cell_iri}}
+    object_diagram:inModel model
+  ]
+  {%- endfor %}
+  {# Cell attributes #}
+  {%- for attr_key,attr_val in cell.attributes.items() %}
+  ci {{cell_iri}}_attr_{{attr_key}} : drawio:CellAttribute [
+    dict:hasKey {{attr_key|to_oml_string_literal}}
+    dict:hasValue {{attr_val|to_oml_string_literal}}
+    drawio:attributeOf {{cell_iri}}
+    object_diagram:inModel model
+  ]
+  {%- endfor %}
+
+  {# Recursively write out children #}
+  {%- for child in cell.children %}
+  {{ write_cell(page_index, child) }}
+  {%- endfor -%}
+{%- endmacro %}
+
+description <{{namespaces.description}}#> as my_drawio {
+
+  uses <{{namespaces.drawio}}#> as drawio
+  uses <{{namespaces.object_diagram}}#> as object_diagram
+  uses <{{namespaces.dict}}#> as dict
+
+  ci model : drawio:Model [
+    drawio:isCompressed {{ "true" if file.compressed else "false"}}
+    drawio:hasDrawioVersion {{file.version|to_oml_string_literal}}
+  ]
+
+  {# Pages #}
+  {%- for page_index, page in enumerate(file.pages) %}
+  ci p{{page_index}} : drawio:Page [
+    drawio:ofModel model
+    drawio:hasDrawioId {{page.id|to_oml_string_literal}}
+    drawio:hasName {{page.name|to_oml_string_literal}}
+    object_diagram:inModel model
+  ]
+
+  {%- for attr_key, attr_val in page.attributes.items() %}
+  ci p{{page_index}}_a_{{attr_key}} : drawio:PageAttribute [
+    dict:hasKey {{attr_key|to_oml_string_literal}}
+    dict:hasValue {{attr_val|to_oml_string_literal}}
+    drawio:ofPage p{{page_index}}
+    object_diagram:inModel model
+  ]
+  {%- endfor %}
+
+  {# Cells #}
+  {{ write_cell(page_index, page.root) }}
+
+  {%- endfor %}
+
+}

drawio2pm/pm_as.py → drawio2oml/pm/abstract_syntax.py


+ 8 - 5
drawio2pm/convert.py

@@ -5,7 +5,7 @@ if __name__ == "__main__":
     argparser = argparse.ArgumentParser(
         description = "Parses .drawio files as Process Models and writes them as OML descriptions.")
     argparser.add_argument('inputfile', help="The process model MUST be on the first layer of the first page of this file.")
-    argparser.add_argument('-o', '--output', metavar='FILE', nargs=1, help="OML output file. If not specified, output will be printed to stdout.")
+    argparser.add_argument('-o', '--output', metavar='FILE TRACE_FILE', nargs=2, help="OML output file. If not specified, output will be printed to stdout.")
     args = argparser.parse_args() # exits on error
 
     from drawio2py import parser, abstract_syntax
@@ -27,9 +27,12 @@ if __name__ == "__main__":
 
     if args.output == None:
         import sys
-        oml_generator.write_oml(pm_asyntax,
-            input_filename=args.inputfile, ostream=sys.stdout)
+        oml_generator.write_oml(input_filename=args.inputfile,
+             pm_model=pm_asyntax, ostream=sys.stdout,
+             traceability_links=traceability_links, ostream_trace=sys.stdout)
     else:
         with open(args.output[0], 'wt') as f:
-            oml_generator.write_oml(pm_asyntax,
-                input_filename=args.inputfile, ostream=f)
+            with open (args.output[1], 'wt') as f2:
+                oml_generator.write_oml(input_filename=args.inputfile,
+                     pm_model=pm_asyntax, ostream=f,
+                     traceability_links=traceability_links, ostream_trace=f2)

+ 119 - 0
drawio2oml/pm/oml_generator.py

@@ -0,0 +1,119 @@
+import io
+import os
+import typing
+
+import jinja2
+
+from drawio2oml.pm import abstract_syntax as pm_as
+from drawio2oml.pm import trace_abstract_syntax as trace_as
+from drawio2oml import util
+
+# Mapping from Python class to OML concept
+TYPENAMES = {
+    pm_as.InitialNode: "pm:Initial",
+    pm_as.FinalNode: "pm:Final",
+    pm_as.Activity: "pm:Activity",
+    pm_as.Artifact: "pm:Artifact",
+    pm_as.CtrlInPort: "pm:CtrlInputPort",
+    pm_as.CtrlOutPort: "pm:CtrlOutputPort",
+    pm_as.DataInPort: "pm:DataInputPort",
+    pm_as.DataOutPort: "pm:DataOutputPort",
+    pm_as.ForkJoin: "pm:ForkJoin",
+    pm_as.CtrlFlowConnection: "pm:CtrlFlow",
+    pm_as.DataFlowConnection: "pm:DataFlow",
+}
+
+def assign_names(pm_model: pm_as.ProcessModel) -> typing.Dict[pm_as.Element, str]:
+    """Assign unique names to all the elements in the process model, in a deterministic fashion"""
+    names = {
+        pm_model.initial: "initial",
+        pm_model.final: "final",
+    }
+    names.update({
+        artifact: "artifact_"+str(idx) for (idx,artifact) in enumerate(pm_model.artifacts)
+    })
+    names.update({
+        activity: "activity_"+str(idx) for (idx,activity) in enumerate(pm_model.activities)
+    })
+    for a_idx, activity in enumerate(pm_model.activities):
+        for p_idx, port in enumerate(util.concat(activity.ctrl_in, activity.ctrl_out, activity.data_in, activity.data_out)):
+            names[port] = "activity_"+str(a_idx)+"_port_"+str(p_idx);
+    names.update({
+        forkjoin: "forkjoin_"+str(idx) for (idx,forkjoin) in enumerate(pm_model.forkjoins)
+    })
+    names.update({
+        ctrl_flow: "ctrl_flow_"+str(idx) for (idx,ctrl_flow) in enumerate(pm_model.ctrl_flows)
+    })
+    names.update({
+        data_flow: "data_flow_"+str(idx) for (idx,data_flow) in enumerate(pm_model.data_flows)
+    })
+    return names
+
+
+def write_pm_oml(
+    input_filename: str,
+    pm_model: pm_as.ProcessModel,
+    pm_names: typing.Dict[pm_as.Element, str],
+    ostream: io.TextIOBase,
+    output_namespace: str = "http://ua.be/sdo2l/description/artifacts/my_pm",
+    namespaces=util.DTDESIGN_NAMESPACES):
+    """
+    Generate an OML description of a process model.
+    Parameters:
+      input_filename: has no precise semantics - only written to the output in a comment
+      pm_model: the parsed process model to write as an OML description
+      pm_names: mapping from every element in the process model to a unique name
+      ostream: stream to write OML output to (e.g., stdout, a file, ...)
+      output_namespace: namespace for the to-be-generated OML description
+      namespaces: namespaces of vocabularies to use
+    """
+
+    environment = jinja2.Environment(
+        loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
+    environment.filters['to_oml_string_literal'] = util.to_oml_string_literal
+    template = environment.get_template("oml_template_pm.j2")
+
+
+    for piece in template.generate(
+            model=pm_model,
+            input_filename=input_filename,
+            enumerate=enumerate,
+            concat=util.concat,
+            pm_names=pm_names,
+            types=TYPENAMES,
+            output_namespace=output_namespace,
+            namespaces=namespaces):
+        ostream.write(piece)
+
+
+def write_traceability_oml(
+    input_filename: str,
+    traceability_links: typing.List[trace_as.TraceabilityLink],
+    pm_names: typing.Dict[pm_as.Element, str],
+    ostream: io.TextIOBase,
+    output_namespace: str = "http://ua.be/sdo2l/description/artifacts/my_trace",
+    namespaces=util.DTDESIGN_NAMESPACES):
+    """
+    Generate an OML description of the traceability links between a Drawio-description and a PM-description.
+    Parameters:
+      input_filename: has no precise semantics - only written to the output in a comment
+      traceability_links: list of traceability links to write as an OML description
+      ostream: stream to write OML output to (e.g., stdout, a file, ...)
+      output_namespace: namespace for the to-be-generated OML description
+      namespaces: namespaces of vocabularies to use
+    """
+    environment = jinja2.Environment(
+        loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
+    environment.filters['to_oml_string_literal'] = util.to_oml_string_literal
+    trace_template = environment.get_template("oml_template_trace.j2")
+
+    for piece in trace_template.generate(
+            traceability_links=traceability_links,
+            pm_names=pm_names,
+            input_filename=input_filename,
+            enumerate=enumerate,
+            concat=util.concat,
+            types=TYPENAMES,
+            output_namespace=output_namespace,
+            namespaces=namespaces):
+        ostream_trace.write(piece)

+ 15 - 15
drawio2pm/template.oml

@@ -2,39 +2,39 @@
 // Input file: {{input_filename}}
 // Generator: https://msdl.uantwerpen.be/git/jexelmans/drawio2pm
 
-description <{{namespaces.description}}#> as {{namespaces.shorthand}} {
+description <{{description_namespace}}#> as my_trace {
 
   uses <{{namespaces.pm}}#> as pm
   uses <{{namespaces.object_diagram}}#> as object_diagram
 
   ci model : pm:Model []
 
-  ci {{names[model.initial]}} : {{types[model.initial.__class__]}} [
+  ci {{pm_names[model.initial]}} : {{types[model.initial.__class__]}} [
     object_diagram:inModel model
   ]
 
-  ci {{names[model.final]}} : {{types[model.final.__class__]}} [
+  ci {{pm_names[model.final]}} : {{types[model.final.__class__]}} [
     object_diagram:inModel model
   ]
 
   {%- for artifact in model.artifacts %}
 
-  ci {{names[artifact]}} : {{types[artifact.__class__]}} [
+  ci {{pm_names[artifact]}} : {{types[artifact.__class__]}} [
     object_diagram:inModel model
   ]
   {%- endfor %}
 
   {%- for activity in model.activities %}
 
-  ci {{names[activity]}} : {{types[activity.__class__]}} [
+  ci {{pm_names[activity]}} : {{types[activity.__class__]}} [
     pm:hasName {{activity.name|to_oml_string_literal}}
     object_diagram:inModel model
   ]
 
   {%- for port in concat(activity.ctrl_in, activity.ctrl_out, activity.data_in, activity.data_out) %}
 
-  ci {{names[port]}} : {{types[port.__class__]}} [
-    pm:ofActivity {{names[activity]}}
+  ci {{pm_names[port]}} : {{types[port.__class__]}} [
+    pm:ofActivity {{pm_names[activity]}}
     object_diagram:inModel model
   ]
   {%- endfor %}
@@ -42,25 +42,25 @@ description <{{namespaces.description}}#> as {{namespaces.shorthand}} {
 
   {%- for forkjoin in model.forkjoins %}
 
-  ci {{names[forkjoin]}} : {{types[forkjoin.__class__]}} [
+  ci {{pm_names[forkjoin]}} : {{types[forkjoin.__class__]}} [
     object_diagram:inModel model
   ]
   {%- endfor %}
 
   {%- for ctrl_flow in model.ctrl_flows %}
 
-  ri {{names[ctrl_flow]}} : {{types[ctrl_flow.__class__]}} [
-    from {{names[ctrl_flow.src]}}
-    to {{names[ctrl_flow.tgt]}}
+  ri {{pm_names[ctrl_flow]}} : {{types[ctrl_flow.__class__]}} [
+    from {{pm_names[ctrl_flow.src]}}
+    to {{pm_names[ctrl_flow.tgt]}}
     object_diagram:inModel model
   ]
   {%- endfor %}
 
   {%- for data_flow in model.data_flows %}
-  
-  ri {{names[data_flow]}} : {{types[data_flow.__class__]}} [
-    from {{names[data_flow.src]}}
-    to {{names[data_flow.tgt]}}
+
+  ri {{pm_names[data_flow]}} : {{types[data_flow.__class__]}} [
+    from {{pm_names[data_flow.src]}}
+    to {{pm_names[data_flow.tgt]}}
     object_diagram:inModel model
   ]
   {%- endfor %}

+ 21 - 0
drawio2oml/pm/oml_template_trace.j2

@@ -0,0 +1,21 @@
+// Warning: Generated Code! Do not edit!
+// This file contains the traceability links from a Drawio input file to a parsed Process Model.
+// Input file: {{input_filename}}
+// Generator: https://msdl.uantwerpen.be/git/jexelmans/drawio2pm
+
+description <{{description_namespace}}#> as my_trace {
+
+  uses <{{namespaces.pm}}#> as pm
+  uses <{{namespaces.object_diagram}}#> as object_diagram
+
+  extends <{{namespaces.my_dio}}#> as my_dio
+  extends <{{namespaces.my_pm}}#> as my_pm
+
+  {%- for trace_link in traceability_links %}
+
+  ri trace_drawio_{{trace_link.dio.id}}_{{names[trace_link.pm]}} : object_diagram:Link [
+    from my_dio:cell_{{trace_link.dio.id}}
+    to my_pm:{{names[trace_link.pm]}}
+  ]
+  {%- endfor %}
+}

+ 2 - 1
drawio2pm/parser.py

@@ -1,6 +1,7 @@
 from typing import List
 from drawio2py import abstract_syntax as dio_as
-from drawio2pm import pm_as, trace_as
+from drawio2oml.pm import abstract_syntax as pm_as
+from drawio2oml.pm import trace_abstract_syntax as trace_as
 
 class ParseError(Exception):
     pass

+ 1 - 1
drawio2pm/trace_as.py

@@ -2,7 +2,7 @@
 
 from dataclasses import dataclass, field
 from drawio2py import abstract_syntax as dio_as
-from drawio2pm import pm_as
+from drawio2oml.pm import abstract_syntax as pm_as
 
 @dataclass
 class TraceabilityLink:

+ 29 - 0
drawio2oml/util.py

@@ -0,0 +1,29 @@
+# Reinventing the wheel...
+def concat(*lists):
+    result = []
+    for l in lists:
+        result.extend(l)
+    return result
+
+# Not sure which characters to escape in OML.
+# At the very least, quotes should be escaped:
+def to_oml_string_literal(python_string):
+    return '"' + python_string.replace('"', '\\"') + '"'
+
+
+
+# Namespaces of vocabularies to use
+
+CDF_NAMESPACES = {
+    "dict": "http://flandersmake.be/cdf/vocabulary/dict",
+    "drawio": "http://flandersmake.be/cdf/vocabulary/drawio",
+    "object_diagram": "http://flandersmake.be/cdf/vocabulary/object_diagram",
+    "pm": "http://flandersmake.be/cdf/vocabulary/pm",
+}
+
+DTDESIGN_NAMESPACES = {
+    "dict": "http://ua.be/sdo2l/vocabulary/formalisms/dict",
+    "drawio": "http://ua.be/sdo2l/vocabulary/formalisms/drawio",
+    "object_diagram": "http://ua.be/sdo2l/vocabulary/formalisms/object_diagram",
+    "pm": "http://ua.be/sdo2l/vocabulary/formalisms/pm",
+}

+ 0 - 90
drawio2pm/oml_generator.py

@@ -1,90 +0,0 @@
-import io
-from drawio2pm import pm_as
-
-DTDESIGN_NAMESPACES = {
-    "shorthand": "my_pm",
-    "description": "http://ua.be/sdo2l/description/artifacts/my_pm",
-    "pm": "http://ua.be/sdo2l/vocabulary/formalisms/pm",
-    "object_diagram": "http://ua.be/sdo2l/vocabulary/formalisms/object_diagram",
-    # "dict": "http://ua.be/sdo2l/vocabulary/formalisms/dict",
-}
-
-def to_oml_string_literal(python_string):
-    # Not sure which characters to escape in OML.
-    # At the very least, quotes should be escaped:
-    return '"' + python_string.replace('"', '\\"') + '"'
-
-def write_oml(pm_model: pm_as.ProcessModel, input_filename: str, ostream: io.TextIOBase):
-    import jinja2
-    import os
-
-    environment = jinja2.Environment(
-        loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
-
-    environment.filters['to_oml_string_literal'] = to_oml_string_literal
-
-    template = environment.get_template("template.oml")
-
-    # vertices = [pm_model.initial, pm_model.final]
-    # elements.extend(pm_model.artifacts)
-    # elements.extend(pm_model.activities)
-    # elements.extend(pm_model.forkjoins)
-
-    # edges
-    # elements.extend(pm_model.ctrl_flows)
-    # elements.extend(pm_model.data_flows)
-
-    def concat(*lists):
-        result = []
-        for l in lists:
-            result.extend(l)
-        return result
-
-
-    # We assign unique names to all elements in the PM:
-    names = {
-        pm_model.initial: "initial",
-        pm_model.final: "final",
-    }
-    names.update({
-        artifact: "artifact_"+str(idx) for (idx,artifact) in enumerate(pm_model.artifacts)
-    })
-    names.update({
-        activity: "activity_"+str(idx) for (idx,activity) in enumerate(pm_model.activities)
-    })
-    for a_idx, activity in enumerate(pm_model.activities):
-        for p_idx, port in enumerate(concat(activity.ctrl_in, activity.ctrl_out, activity.data_in, activity.data_out)):
-            names[port] = "activity_"+str(a_idx)+"_port_"+str(p_idx);
-    names.update({
-        forkjoin: "forkjoin_"+str(idx) for (idx,forkjoin) in enumerate(pm_model.forkjoins)
-    })
-    names.update({
-        ctrl_flow: "ctrl_flow_"+str(idx) for (idx,ctrl_flow) in enumerate(pm_model.ctrl_flows)
-    })
-    names.update({
-        data_flow: "data_flow_"+str(idx) for (idx,data_flow) in enumerate(pm_model.data_flows)
-    })
-
-    types = {
-        pm_as.InitialNode: "pm:Initial",
-        pm_as.FinalNode: "pm:Final",
-        pm_as.Activity: "pm:Activity",
-        pm_as.Artifact: "pm:Artifact",
-        pm_as.CtrlInPort: "pm:CtrlInputPort",
-        pm_as.CtrlOutPort: "pm:CtrlOutputPort",
-        pm_as.DataInPort: "pm:DataInputPort",
-        pm_as.DataOutPort: "pm:DataOutputPort",
-        pm_as.ForkJoin: "pm:ForkJoin",
-        pm_as.CtrlFlowConnection: "pm:CtrlFlow",
-        pm_as.DataFlowConnection: "pm:DataFlow",
-    }
-
-    for piece in template.generate(
-            model=pm_model,
-            input_filename=input_filename,
-            enumerate=enumerate,
-            concat=concat,
-            names=names,
-            types=types,
-            namespaces=DTDESIGN_NAMESPACES):
-        ostream.write(piece)

+ 7 - 3
setup.py

@@ -1,7 +1,7 @@
 from setuptools import setup, find_packages
 
 setup(
-    name="drawio-parsers",
+    name="drawio2oml",
     version="1.0.0",
 
     install_requires=[
@@ -9,8 +9,12 @@ setup(
     ],
 
     package_dir={"":"."},
-    packages=["drawio2pm"],
+    packages=["drawio2oml"],
 
     include_package_data=True,
-    package_data={"drawio2pm": ["template.oml"]},
+    package_data={"drawio2oml": [
+        "drawio/template.j2",
+        "pm/pm-template.j2",
+        "pm/trace-template.j2",
+    ]},
 )

File diff suppressed because it is too large
+ 1 - 0
test/data/drawio/overview.drawio


File diff suppressed because it is too large
+ 68 - 0
test/data/drawio/test.drawio


test/data/SlightlyLessTrivialPM.drawio → test/data/pm/SlightlyLessTrivialPM.drawio


test/data/TrivialPM.drawio → test/data/pm/TrivialPM.drawio


+ 0 - 33
test/run_test.py

@@ -1,33 +0,0 @@
-from drawio2py import abstract_syntax as dio_as
-from drawio2py import parser as dio_parser
-from drawio2pm import parser as pm_parser
-from drawio2pm.oml_generator import write_oml
-import sys
-import os
-import pprint
-
-if __name__ == "__main__":
-    DATADIR = os.path.join(os.path.dirname(__file__), "data")
-
-    def run_test(filename):
-        dio_asyntax = dio_parser.Parser.parse(os.path.join(DATADIR, filename))
-
-        # pprint.pprint(dio_asyntax, indent=2, compact=True)
-
-        for page_index, page in enumerate(dio_asyntax.pages):
-            for layer_index, layer in enumerate(page.root.children):
-                try:
-                    print("parsing page", page_index, "layer", layer_index, "as process model...")
-                    pm_asyntax, traceability_links = pm_parser.parsePM(layer)
-
-                    pprint.pprint(pm_asyntax, indent=2, compact=True)
-
-                except pm_parser.ParseError as e:
-                    print("Could not parse page", page_index)
-                    continue
-
-                write_oml(pm_asyntax, input_filename=filename, ostream=sys.stdout)
-                print()
-
-    run_test("TrivialPM.drawio")
-    print("All good")

+ 85 - 0
test/run_tests.py

@@ -0,0 +1,85 @@
+import sys
+import os
+import io
+import pprint
+
+from drawio2py import abstract_syntax as dio_as
+from drawio2py import parser as dio_parser
+from drawio2py import generator as dio_generator
+from drawio2oml.drawio import oml_generator as dio_oml_generator
+from drawio2oml.pm import parser as pm_parser
+from drawio2oml.pm import oml_generator as pm_oml_generator
+
+if __name__ == "__main__":
+    DATADIR = os.path.join(os.path.dirname(__file__), "data")
+
+    class DummyOutput:
+        def write(self, str):
+            pass
+
+    def run_drawio_test(filename):
+        # Parse (1st time):
+        asyntax = dio_parser.Parser.parse(os.path.join(DATADIR,filename))
+
+        # Print abstract syntax:
+        # pprint.pprint(asyntax, indent=2, compact=True)
+
+        # Generate .drawio (1st time):
+        csyntax = io.BytesIO()
+        dio_generator.generate(asyntax, csyntax)
+        csyntax.seek(0)
+
+        # Print generated .drawio
+        # print(csyntax.getvalue())
+
+        # Parse (2nd time):
+
+        asyntax2 = dio_parser.Parser.parse(csyntax)
+
+        # Generate .drawio (2nd time):
+        csyntax2 = io.BytesIO()
+        dio_generator.generate(asyntax2, csyntax2)
+        csyntax2.seek(0)
+
+        if (csyntax.getvalue() != csyntax2.getvalue()):
+            # print(csyntax.getvalue())
+            # print(csyntax2.getvalue())
+            raise Exception("Files differ after round-trip!")
+
+        dio_oml_generator.write_oml(
+            drawio_file=asyntax,
+            drawio_names=dio_oml_generator.assign_names(asyntax),
+            ostream=DummyOutput())
+        print(filename, "OK")
+
+
+    def run_pm_test(filename):
+        dio_asyntax = dio_parser.Parser.parse(os.path.join(DATADIR, filename))
+
+        # pprint.pprint(dio_asyntax, indent=2, compact=True)
+
+        for page_index, page in enumerate(dio_asyntax.pages):
+            for layer_index, layer in enumerate(page.root.children):
+                try:
+                    pm_asyntax, traceability_links = pm_parser.parsePM(layer)
+
+                    # pprint.pprint(pm_asyntax, indent=2, compact=True)
+
+                except pm_parser.ParseError as e:
+                    print("Could not parse page", page_index)
+                    continue
+
+                pm_names = pm_oml_generator.assign_names(pm_asyntax)
+
+                pm_oml_generator.write_pm_oml(
+                    input_filename=filename,
+                    pm_model=pm_asyntax,
+                    pm_names=pm_names,
+                    ostream=DummyOutput())
+                print(filename, "OK")
+
+    run_drawio_test("drawio/test.drawio")
+    run_drawio_test("drawio/overview.drawio")
+    run_pm_test("pm/TrivialPM.drawio")
+    run_pm_test("pm/SlightlyLessTrivialPM.drawio")
+    print("All good")