TypeScript library for AM / RM / OPTs

@ian.mcnicoll motivated me to start working on a TypeScript generator.

Here are the TypeScript classes for RM 1.0.3 (rename the extension .md to .zip):

openehr_typescript_models_rm103.md (140.2 KB)

AM classes are also generated. I still need to port JSON serialization code (all generated) to TypeScript. This will add reading/writing JSON data instances and archetypes/templates.

Would something like this be useful for frontend implementation?

This is the first WIP version. I’ll update the attached file with new code.

Preview of the OperationalTemplate:

/**
* Root object of an operational template. An operational template is derived from a TEMPLATE definition and the ARCHETYPEs and/or TEMPLATE_OVERLAYs mentioned by that template by a process of flattening, and potentially removal of unneeded languages and terminologies.
* 
* An operational template is used for generating and validating RM-canonical instance data, and also as a source artefact for generating other downstream technical artefacts, including XML schemas, APIs and UI form definitions.
* BMM name: OPERATIONAL_TEMPLATE
* BMM ancestors: AUTHORED_ARCHETYPE
* isAbstract: false | isPrimitiveType: false | isOverride: false
*/
export class OperationalTemplate extends AuthoredArchetype {
  /**
  * Compendium of flattened terminologies of archetypes externally referenced from this archetype, keyed by archetype identifier. This will almost always be present in a template.
  * BMM name: component_terminologies | BMM type: Hash<String,ARCHETYPE_TERMINOLOGY>
  * isMandatory: false | isComputed: false | isImRuntime: false | isImInfrastructure: false | existence: 0..1
  */
  componentTerminologies?: Map<string, ArchetypeTerminology>;

  /**
  * Directory of term definitions as a two-level  table. The outer hash keys are term codes,  e.g. "at4", and the inner hash key are term  attribute names, e.g. "text", "description" etc.
  * BMM name: terminology_extracts | BMM type: Hash<String,ARCHETYPE_TERMINOLOGY>
  * isMandatory: false | isComputed: false | isImRuntime: false | isImInfrastructure: false | existence: 0..1
  */
  terminologyExtracts?: Map<string, ArchetypeTerminology>;

  constructor(rmRelease: string, isGenerated: boolean, originalLanguage: TerminologyCode, archetypeId: ArchetypeHrid, isDifferential: boolean, terminology: ArchetypeTerminology, definition: CComplexObject) {
    super(rmRelease, isGenerated, originalLanguage, archetypeId, isDifferential, terminology, definition);
  }

  equals(other: any): boolean {
    if (this === other) return true;
    if (!this || !other || (typeof this !== "object" && typeof other !== "object")) return this === other;
    let otherAsOperationalTemplate: OperationalTemplate = other as OperationalTemplate;
    return this.adlVersion === otherAsOperationalTemplate.adlVersion &&
      this.rmRelease === otherAsOperationalTemplate.rmRelease &&
      this.isGenerated === otherAsOperationalTemplate.isGenerated &&
      this.buildUid?.equals(otherAsOperationalTemplate.buildUid) &&

Interesting task :thinking:

What is the source (input) of your generating tool? Will the tool be opensourced/licensed?

What is your plan above with JSON? Should that be part of an API client library?

Source (input) are BMM files for AM and RM.

The next generator then takes OPTs to generate “domain model” classes as shown in this post.

Since the generated “domain model” classes extend the RM classes, they return their canonical JSON representation of e.g. COMPOSITION (example for the vital signs composition class used in the linked post above):

Notice the list of other classes on the left of the screenshot. There are 136 classes for this template. These are all generated from the OPT and extend RM classes:

Top level TEncounterVitalSignsComposition class converts the entire hierarchy to JSON. It also de-serializes JSON to TEncounterVitalSignsComposition.

With AM classes reading of JSON representation of archetypes/templates is possible.


The plan for the TypeScript version is to be used as a frontend client library. Either with UI components or headless. React and Vue components could be included and forms generated.

The same library also works on Node.js in case somebody would want to use it there.

The plan is to opensource at least some of the RM classes for free. The complete version could be available as “source available” license.

A SaaS option could be available for generating the code for OPTs.

I would like to open source the tool but it will probably be available as “source available” license since “open source != free” :blush:

Sounds like a good plan, in general. Thanks for sharing.

Some thoughts:

  • BMM classes/files might not be complete comparing to UML we maintain. I’m also (passively) working on generating enriched BMM from UML. Those might be a better/safer fit for your project.
  • we learned over the last years that BMM or RM types are not always suitable for frontend app level consumptions; they are more suitable for backend platform services. Just as example, there are attributes that has be set by service on runtime, based on service processes, which from app perspective are readonly and mostly not transparent.
  • you should have some thoughts about what should be the repository to store this ref implementation and who /how should it be maintained in time (continuity plan)

Thank you for the feedback Sebastian!

  • I’ve learned that about BMMs soon after I started to work on openEHR. Luckily Thomas and Pieter were helpful to update them so that they are in sync with UML now – at least I haven’t encountered any problems. Of course BMM could be extended to specify even more information about the model.
  • I had to accept early that openEHR has focused mostly on the backend as you mentioned. This leaves openEHR users locked-in to whoever develops their frontend apps – they can change their CDR vendor but changing app vendor(s) would be too expensive in most cases.
  • The best approach would be to publish all generated code (and tools) under the openEHR.org. This way it is independent of me. I do have BuildEHR.org as a plan B.

@borut.jures I’m happy to help publish this work on GitHub for you, either under the openEHR GitHub org or somewhere else. Do you have any co-maintainers? I’m keen that official openEHR projects should probably not rely on a single person.

Thank you @marcusbaw for offering a home for this project. However, based on the lack of interest over the last two years, the project is better left in its deep sleep :blush:

I understand that @erik.sundvall has started some work on this. I’d certainly be very happy to assist, as I need it, or have already created similar code.

Certainly sounds like a collaboration between the three of you @erik.sundvall @ian.mcnicoll @borut.jures could result in a well-supported, capable TS library for openEHR. I do think this is the sort of thing we are going to have to do - collaborate cross-organisationally - if we seriously want openEHR adopted at global scale. The libraries need to have multiple maintainers, can’t be abandoned, need to have plenty of GitHub stars and a decent README.md etc.

What a coincidence to see this thread fire up again.

This morning I happened to fire up my AI agents to go on implementing AM/ADL support for Ehrtslib since it would help illustrate some things for our CDR catalyst project.

You are very welcome to help out. If openEHR later wants to have it under its wings then we could move it there.

Sounds like you 3 could boil down the best of all 3 pieces of work into a single ‘official’ openEHR.ts repo? I did a similar thing a few years back, bringing together the maintainers of the (at the time) four or more different partial NHS Number libraries in Python, to coalesce them into a single, best one. That approach worked and the project’s still going (and we’re looking to do the same in Rust soon too).

I am happy to help out from the organisational GitHub perspective, adopting a repo, organising access, CI, and also I’m quite good at ‘pimping’ READMEs and repos to make them read well and look good.

It’s very likely that the input sources (RM, BMM etc), test suite, conformance panel, and spec.mdwould be quite reusable for others wanting to build something in other languages.

My secret plan was of course trying to generate a Python implementation too, or better, inspire some Python pro/wizkid to do it. :slight_smile:

But I’d like to see if the approach works OK for Typescript first. Also tweaking and comparing server-side performance to Java openEHR implementations once Microsoft gets the TS native speedup public and stable would be interesting.

Then of course finally making the Contribution Builder and REST patterns described in our old REST BMC paper would be nice.

Also running an alternative Ehrtslib class generator from @thomas.beale’s new BMML way of describing model semantics, would be interesting.

We are also working internally on openEHR Typescript SDK. It could be that it aligns well with this project and the intentions states above - then we can also participate/collaborate to some extent.

Our version is designed to be used on top of a CDR (has support generic openEHR APIs as well as Cadasto specifics), with SMART-on-openEHR (and FHIR) connectivity. Code contains also RM/AM generated based on BMM. It is still a early SDK, not ready to be used, but we are working on it.
In parallel we also working on a PHP and a GO SDK with similar capabilities. I am considering all these for an open-source release in a near future.

I am also curios what functionalities/capabilities you will consider for this library. I can also assist with at least BMM files related aspects.

@sebastian.iancu in fact you have already contributed the BMM files that generated the original Ehrtslib stubs in the /generated subdirectory. In a branch that generator has been updated and i’ll soon rerun it to spot differences.Where are the latest BMMs now?