Skip to content

Languages and Ecosystems ​

How one Kotlin core writes four languages and reaches the JVM, .NET and Node. The reasons are recorded in ADR 007 and ADR 014; modules and layers are on Architecture.

Gradle, Maven and the web app call core directly; the .NET tool, the npm package and the archive start the CLI, which calls core; core renders every language from one graph onto the runtime package of its ecosystem

Two ways into core ​

Every language is written in core; an entry point only chooses one.

  • Directly. The Gradle plugin, the Maven plugin and the web app run on the JVM anyway and call core's *Plugin classes in their own process.
  • Through the command-line tool. Everything outside the JVM starts the CLI bpmn-to-code, which calls the same *Plugin classes. The .NET and npm packages contain no generator, only the CLI jars and a launcher that starts them on Java 21 from JAVA_HOME or the PATH:
PackageLauncherHow a project uses it
Miragon.BpmnToCodeProgram.cs of a .NET tooldotnet tool exec, or the MSBuild package, which runs it before the project compiles and brings the runtime of the same version
@miragon/bpmn-to-codelauncher.js, registered under binbpmn-to-code generate-api … in a package.json script; the runtime is a peer dependency of exactly the same version
Release archive, Homebrewbin/bpmn-to-codeAnywhere else; the archive bundles its own Java runtime (jlink)

Per language ​

LanguageRendered byRuntime typesGenerated in its ecosystem byChecked by
Kotlinbuilder/kotlin, templates/kotlinio.miragon:bpmn-to-code-runtime (Maven Central)Gradle or Maven pluginGolden files; compiled in NestedSubProcessCompilationTest
Javabuilder/java, templates/javaio.miragon:bpmn-to-code-runtime (Maven Central)Gradle or Maven pluginGolden files; compiled in JavaProcessApiBuilderTest
C#builder/csharp, templates/csharpMiragon.BpmnToCode.Runtime (NuGet)Miragon.BpmnToCode.MSBuild during dotnet build, or the .NET tool Miragon.BpmnToCodeGolden files; dotnet test in packages/nuget/BpmnToCode.Runtime.Tests
TypeScriptbuilder/typescript, templates/typescript@miragon/bpmn-to-code-runtime (npm)@miragon/bpmn-to-code in an npm scriptGolden files; npm test in packages/npm/bpmn-to-code-runtime

A builder maps the language-neutral graph to a template model and handles keywords, escaping and imports; the FreeMarker template writes the code around it. CodeGenerationAdapter picks the builders of a language from one map.

Where the parts live ​

text
bpmn-to-code-core/src/main/
├─ kotlin/io/miragon/bpmn/adapter/outbound/codegen/
│  ├─ flow/, definitions/            language-neutral graphs
│  └─ builder/<language>/            graph → template model, syntax, imports
└─ resources/io/miragon/bpmn/codegen/templates/<language>/   FreeMarker templates
bpmn-to-code-core/src/test/resources/api/   golden files per language
bpmn-to-code-runtime/                       runtime types for Kotlin and Java
bpmn-to-code-cli/                           command-line tool and its archives
packages/nuget/                             BpmnToCode.Runtime (+ .Tests), BpmnToCode.Tool, BpmnToCode.MSBuild
packages/npm/                               bpmn-to-code-runtime (+ test/), bpmn-to-code

Build and release ​

WorkflowWhat it does
build-backend.ymlRuns the Gradle build on the JVM alone and smoke-tests the CLI archive
build-packages.ymlWhen core, the CLI or packages/ change: builds the CLI and runs the package tests, which generate C# and TypeScript with it and compile and run them against the runtime packages
publish-cli.ymlBuilds and starts one archive per platform and attaches it to the release
publish-homebrew.ymlUpdates the formula in Miragon/homebrew-tap for a stable release
publish-to-nuget.ymlPacks the three NuGet packages, smoke-tests tool and MSBuild, pushes them only once the repository variable PUBLISH_NUGET is true
publish-to-npm.ymlStages both npm packages, smoke-tests them on three operating systems, publishes them only once PUBLISH_NPM is true

release-please.yml calls all of them; every artifact carries the one version of gradle.properties (ADR 011). Details in Releasing.

Adding a language ​

  1. A value in OutputLanguage, which Gradle, Maven and the CLI accept from then on, and an option in the form of the web app.
  2. A package builder/<language> and a folder templates/<language>, registered in CodeGenerationAdapter.
  3. Golden files under src/test/resources/api/, and tests next to the runtime package that compile the output with the language's own compiler.
  4. A runtime package in the language's registry, if the output refers to runtime types, and a package that starts the CLI there.
  5. A getting-started page and a line in ADR 007.