From 950dcf1d2b6b6487b49801c4d4c671a063480564 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Wed, 20 May 2026 14:19:16 +0200 Subject: [PATCH] docs(developer): write up basic internal docs on kmc modules Fixes: #13672 Test-bot: skip Build-bot: skip --- developer/docs/internal/kmc-modules.md | 94 ++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 developer/docs/internal/kmc-modules.md diff --git a/developer/docs/internal/kmc-modules.md b/developer/docs/internal/kmc-modules.md new file mode 100644 index 0000000000..7d61cf3754 --- /dev/null +++ b/developer/docs/internal/kmc-modules.md @@ -0,0 +1,94 @@ +--- +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 + +```ts + 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. + +* See [Keyman Developer Messaging](developer-messaging) for further detail on + messages. + +### 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. +