Skip to content

1.0: per-port CLI hook to load an app's custom provider (loaders already accept providers) #158

Description

@dmealing

Summary

The metadata loaders already accept consumer providers in every language — a runtime/library app that loads the metamodel can plug in its own provider and it merges on top of core. The gap is purely at the CLI / build-tool layer: on non-TS ports there is no idiomatic way to hand the app's provider to the loader the CLI already uses.

Verified: the library path works as designed

  • TS: loadMemory({ providers }) / new MetaDataLoader({ registry }).
  • Python: MetaDataLoader(providers=[*core_providers, my_provider])loader/meta_data_loader.py __init__(providers=...)compose_registry(...).

So an application loading the metamodel at runtime can extend it, in both languages, today. This is not the problem.

The gap: the CLI can't supply the provider (non-TS)

  • TS CLI: reads metaobjects.config.ts providers and threads them into loadMemory. ✅
  • Python CLI: _cmd_gen / _verify_codegen_load_rootMetaDataLoader.from_directory(dir) — the convenience classmethod that uses core providers only, with no config to name a consumer provider. So the bare metaobjects gen / verify cannot load an app's custom subtype, even though the underlying MetaDataLoader would accept it. ❌ This is the concrete missing piece.
  • Java / C#: codegen runs as a build plugin (Maven/Gradle / MSBuild) with the project classpath, so it can see a compiled consumer provider — but that provider path is undocumented (own-your-codegen covers custom generators, not custom providers/subtypes).

Why it must load the provider CLASS, not a JSON file

A provider carries code, not just declarations:

  • factory is always code (FactoryMap = (typeId, name) => MetaData) — even the data-driven defineProviderFromData path takes a code factory map.
  • TypeDefinition.validate?: NodeValidator — an optional imperative validator (custom enforcement logic).

JSON can express the declarative surface (types / attrs / childRules / descriptions) but not the factory or a validator. So the mechanism has to load the app's native provider class in each language.

No single uniform mechanism — idiomatic per port (A4)

This is not a parity bug; it is inherent:

  • Interpreted (TS / Python): standalone CLI + a config that names/imports the provider module.
  • Compiled (Java / C#): build-plugin + classpath/assembly (cannot import a source module at CLI runtime).

Consistent with the ratified A4 ("own your codegen is idiomatic per-port").

Proposed for 1.0

  1. Python CLI provider hook — the concrete missing piece: a metaobjects.config.py / entry-point / --provider module:symbol that _load_root imports and passes as MetaDataLoader(providers=[*core_providers, <that>]). Parity with TS config.providers.
  2. Document the JVM / C# provider-via-classpath path in own-your-codegen.md (custom providers / subtypes, not just generators).
  3. TS migrate offline path — already tracked as meta migrate offline paths don't thread config providers (custom subtypes fail) #157 (offline loadMemory doesn't thread config.providers).
  4. Optional convenience — for behaviorless subtypes (attr-only, factory = a shared default like new MetaView), support a pure-declarative provider JSON so the common case needs zero per-language code. A deep adopter's view.* subtype is exactly this case — it forced a "strip the custom nodes" workaround to run the non-TS model-gen CLI.

1.0 readiness

Add an F3/D4 line: non-TS CLIs need their idiomatic consumer-provider load hook; the loaders already accept providers — only the CLI convenience path (from_directory) is core-only.

(Supersedes the earlier 'just make it a JSON file' framing: the loaders already work; this is a per-port CLI/build-tool load hook, and it must load a native provider class because providers carry factory + optional validator code.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions