spiegel-keyman/developer/docs/internal/kmc-modules.md
Marc Durdin 950dcf1d2b docs(developer): write up basic internal docs on kmc modules
Fixes: #13672
Test-bot: skip
Build-bot: skip
2026-05-20 14:19:16 +02:00

3.1 KiB

title
kmc module interfaces

kmc, aka 'Keyman Compiler' is designed as a set of activity modules (e.g. @keymanapp/kmc-kmn) which are all access with a common interface KeymanCompiler, together with a module @keymanapp/kmc that provides command line access to these modules.

The modules can also be accessed programmatically through these interfaces and classes, defined in compiler-interfaces.ts:

  • KeymanCompiler
  • KeymanCompilerArtifact
  • KeymanCompilerArtifactOptional
  • KeymanCompilerArtifacts
  • KeymanCompilerResult

The following interfaces and classes are also relevant:

  • CompilerCallbacks
  • CompilerEvent
  • CompilerOptions
  • CompilerError

Each module defines one implementation of KeymanCompiler, and extensions of KeymanCompilerArtifact, KeymanCompilerResult, and CompilerOptions.

A sample run

  const callbacks = new MyCompilerCallbacks();
  const options: KmnCompilerOptions = { ... };
  const compiler = new KmnCompiler();
  if(!await compiler.init(callbacks, options)) { ... }
  const result = await compiler.run(infile, outfile);
  if(result) {
    if(!await compiler.write(result.artifacts)) { ... }
  }

Design requirements for activity modules

Some design requirements for the activity modules:

  • Isolated from I/O
  • Cross-platform
  • Error and message management
  • Activity artifacts
  • Stateless
  • Unit test endpoint pattern

Isolated from I/O

Modules must be isolated from all I/O (module loading is assumed to be available); CompilerCallbacks provides access to external files if they are required. No console messages may be emitted in production builds.

Cross-platform

Modules must run on both Node and Web platforms, thus must not import node: libraries or libraries that are incompatible with either platform.

Error and message management

Compiler messages -- errors relating to user data -- must be emitted using the CompilerCallbacks.reportMessage function and defined as a CompilerEvent using the common messages.ts file pattern.

Internal errors should be thrown as exceptions, but these should be handled within the module, rather than pushed back up to the caller. The top-most exception handler in the module should use the Fatal_UnexpectedException({e:e}) pattern to report the error to the user.

Activity artifacts

The activity will produce a set of in-memory artifacts using an extension of the KeymanCompilerArtifact interface. These will be written to disk by the compiler using a callback.

Stateless

Each module should be not include internal state between runs; compiler options will persist. This allows the same module instance to be re-used for batch builds.

Unit test endpoint pattern

Any class implementing the KeymanCompiler interface should include a property unitTestEndpoints to make internal functions accessible for test, rather than making the functions public. The only public functions should be implementations of the KeymanCompiler interface.