Morphir Developers' Guide
The purpose of the document is to provide a detailed explanation of how various Morphir code artefacts work. It also documents the standard coding practices adopted for the Morphir project. Finally, it provides a step by step walk-throughs on how various Morphir components are build.
Who this Guide Designed For
- New joiners to the Morphir project to get up to speed the various building blocks of Morphir
- Existing team members intending to improve their abilities on Language Design concepts
##Content
- Getting Started with Morphir \
- Overview of Morphir
- The Morphir Architecture \
- The Morphir SDK \
- [Morphir Commands Processing](Morphir-elm Commands Processing) \
- Interoperability With JavaScript \
- Testing Framework \
- The Morphir IR \
- Overview of the Morphir IR \
- Distribution \
- Package \
- Module \
- Types \
- Values \
- Names \
- The Morphir Frontends \
- The Morphir Backends \
- Working with CODECS \
- NPM and Elm Packages \
- Introduction to Combinator Parsing in Scala \
Getting Started With Morphir
Go Workspace and Module Versions
Morphir is a multi-module Go repo. Local development relies on Go workspaces:
- Use
go.workfor local cross-module development; do not addreplacedirectives togo.mod. - Keep internal dependencies in
go.modpinned to the latest released tags. - For unreleased local changes, add the modules to
go.workand build/test locally. - If a module has no tags yet, prefer a local-only, versioned
go.workreplace as the default workaround; add an initial tag only when you intend to publish and consume that version. - Never commit
go.workorgo.work.sum. - Use
mise run workspace-doctorto diagnose workspace issues and apply local fixes (default createsgo.workif missing and adds versionedgo.workreplaces for missing internal tags).
For setup and troubleshooting details, see DEVELOPING.md.
Industry Patterns (Go Workspaces)
Some large monorepos commit go.work and even use replace directives in go.work:
- Kubernetes: commits a generated
go.worklisting./and./staging/src/k8s.io/*modules. - Grafana: commits
go.workwith manyapps/*andpkg/*modules, plusreplaceentries.
Other popular repos remain single-module and do not use go.work (e.g., Terraform, golang.org/x/tools).
Morphir’s policy differs: we do not commit go.work or go.work.sum, and we never add
replace directives to go.mod. Local development uses go.work only.
Morphir-elm Commands Processing
Morphir-elm Commands Processing
The purpose of the document is to explain what happens when morphir-elm commands are run. This documents also describes each morphir-elm command, options and output/result of the command.
Note: This document is best suited for contributors or anyone interested in understanding how morphir-elm is glued together. You don't need all this information to use Morhpir-elm.
All morphir-elm commands are processed in NodeJS. This is because Elm is not built to
work outside a browser and has no way to interact with the terminal.
Morphir-elm uses the elm javascript-interop (i.e. ports) feature to foster communication between the
NodeJS environment and the Elm platform. Code validation and the generation of the IR happens
withing Elm.
Here's a list of the commands along with the supported options for each command and what they mean.
The following commands are described in this document:
1. morphir-elm make
2. morphir-elm gen
3. morphir-elm develop
4. morphir-elm test
morphir-elm make
###Command Description
This command reads elm sources, translates to Morphir IR and outputs the IR into JSON.
| Option | Requires | Description |
|---|---|---|
-o, --output | <path> | Target file location where the Morphir IR will be saved. (default: "morphir-ir.json") |
-p, --project-dir | <path> | Root directory of the project where morphir.json is located. (default: ".") |
-h, --help | - | Output usage information. |
Command Execution Process
Here's a description of the processes involved with running the morphir-elm make command
The entry point for this command ie specified in morphir-elm-make.js.
Control is handed over to the make function defined in cli.js passing in the project directory (directory where the morphir.json lives) and cli arguments/options.
The cli.make function reads the morphir.json contents, reads the Elm source files (files ending with .elm),
and passes the source files, morphir.json and cli options to Elm using ports.
It is worth mentioning that only messages/data is sent between NodeJS and Elm and Elm notifies NodeJS when something goes wrong, or when the process is complete via commands and subscriptions.
The following ports are used:
- jsonDecodeError - this is used to receive possible jsonDecode error from Elm
- packageDefinitionFromSource - this is used to receive send the source files, morphir.json and cli options to Elm CLI.elm
- packageDefinitionFromSourceResult - this is used to receive the package definition results from elm.
The entry point responsible for the exposing ports to NodeJS can be found here.
The update function within elm is immediately triggered when a message comes in through a port.
Visit the docs on the elm architecture,
and checkout Commands and Subscriptions to get a better understanding on why the update function is called.
The update function identifies which port the message came through and carries out the next action based on that decision.
The Morphir IR is generated after validation and parsing, and a command is sent out to NodeJS to end the process with either a success (which creates the morphir-ir.json and write to it) or with a failure which outputs a failure and message showing where the error might have occurred.
morphir-elm gen
Command Description
This command reads the Morphir IR and generates the target sources in the specified language.
| Option | Requires | Description |
|---|---|---|
-i, --input | <path> | Source location where the Morphir IR will be loaded from. (default: "morphir-ir.json") |
-o, --output | <path> | Target location where the generate code will be saved (default: "./dist") |
-t, --target | <type> | Language to Generate (Scala h SpringBoot cypher tri TypeScript) (default: "Scala") |
-e, --target-version | <version> | Language version to generate. (default: "2.11") |
-c, --copy-deps | <True or False> | Copy the dependencies used by the generated code to the output path (True False) (default: "False") |
-m, --modules-to-include | <comma separated list of module names> | Limit the set of modules that will be included. |
Command Execution Process
Here's a description of the processes involved with running the morphir-elm gen command
The execution process begins with the reading of the Morphir IR from the specified input path. Next, the morphir ir is
stringified and passed into JSON. The resulting object is given to the generate function.
This generate function which does three things
- Subscribes to the jsonDecodeError port
- Subscribes to the generateResults port
- Sends the IR together with options to the Elm program (CLI.elm) via the generate port.
morphir-elm test
###Command Description
This command is used to test the test cases present in the morphir-ir.json.
| Option | Requires | Description |
|---|---|---|
-p, --projectDir | <path> | Root directory of the project where morphir.json is located. (default: ".") |
Command Execution Process
Here's a description of the processes involved with running the morphir-elm make command
This command invokes the test() function defined in cli.js.
It takes the project directory (projectDir) as a argument and read content of the morphir-ir.json as well as the morphir-tests.json.
The testResult() function is called with both arguments.
The testResult() function interfaces with the
CLI.elm which defines the following ports:
- jsonDecodeError - sends jsonDecode error from the Elm (CLI.elm) to JavaScript (cli.js)
- runTestCasesResultError - sends errors resulting from running the test cases from the Elm (CLI.elm) to JavaScript cli.js)
- runTestCasesResult - sends the results of the test cases from the Elm (CLI.elm) to JavaScript cli.js)
- runTestCases - receives the test cases to be run sent from Javascript (cli.js) to Elm (CLI.elm)
morphir-elm develop
Command Description
This command starts a web server and exposes the developer tools via a web UI. The entrypoint for the morphir-elm develop
command is specified in the morphir-elm-develop.js file.
| Option | Requires | Description |
|---|---|---|
-p, --port | <port> | Port to bind the server to. (default: "3000") |
-o, --host | <host> | Host to bind the server to (default: "0.0.0.0") |
-i, --path | <path> | Root directory of the project where the morphir.json is located (default: ".") |
Command Execution Process
Here's a description of the processes involved with running the morphir-elm develop command
The web pages is located inside the sever/web folder of the project directory.
The following endpoints are exposed by the after by the morphir-elm develop command
'/'
'/server/morphir.json - serves the content of the morphir.json file'
'/server/morphir-ir.json - serves the content fo the morphir-ir.json file'
'/server/morphir-tests.json - (GET) serves te content of the morphir-tests.json file'
'/server/morphir-tests.json - (POST) accepts a request as morphir-test.json as request body, creates the morphir-tests.json
and returns the content as response'