Feature Request ποΈ
Provide first-class helpers on the model API to answer "is type X, or does it extend, type Y?" and "what concrete types are assignable to Y?" β without each consumer re-implementing the traversal over getAssignableClassDeclarations().
Use Case
Consumers frequently need to test the runtime/nominal class hierarchy of a model:
- "Is
fqn a subtype of (or equal to) baseFqn?" β e.g. validating that a payload's $class is, or extends, a known base type.
- "Which concrete (non-abstract) declarations are assignable to
baseFqn?" β e.g. building a union/enumeration of valid subtypes (plus the base itself when it is concrete).
Today the building blocks exist (ClassDeclaration.getAssignableClassDeclarations(), getAllSuperTypeDeclarations(), isAbstract()), but there is no concise, discoverable helper for these two very common questions. The only ModelUtil.isAssignableTo(modelFile, typeName, property) is @private and answers a different question (can a type be assigned to a property), so it can't be reused for a plain subtype check.
Possible Solution
Expose two small, pure helpers (on ModelUtil, ModelManager, or a new introspection util β wherever fits best):
/**
* Concrete (non-abstract) declarations assignable to baseFqn: the base itself
* (when concrete) plus all subclasses. Empty array if baseFqn is not in the model.
*/
function getAssignableConcreteTypes(modelManager: ModelManager, baseFqn: string): ClassDeclaration[];
/**
* True when fqn is, or extends, baseFqn (restricted to concrete types).
*/
function isAssignableTo(modelManager: ModelManager, fqn: string, baseFqn: string): boolean;
isAssignableTo can be implemented in terms of getAssignableConcreteTypes (membership test), or more directly by walking getAllSuperTypeDeclarations() from the candidate β implementer's choice. Naming is a suggestion; happy to align with existing conventions (note the @private ModelUtil.isAssignableTo name clash to disambiguate).
Context
In accordproject/template-engine#166 we enforce a runtime class hierarchy (State / Request / Response / Event) both at compile time (building a TypeScript union of the assignable concrete types) and at runtime (checking a payload's $class is-a the base). We implemented these two helpers locally in the template-engine's own utils.ts and had two call sites drift apart during review before centralizing them β a reviewer specifically flagged that the assignability rule should have a single source of truth. This felt like model-level functionality that belongs in Concerto rather than being re-derived by each downstream project.
Detailed Description
- Add the helpers described above with unit tests covering: base type present & concrete (included), base type abstract (excluded), subclass (included/assignable), unrelated type (not assignable), and base type absent from the model (empty /
false).
- Purely additive, no breaking changes.
- Once released, template-engine can drop its local copies and depend on the Concerto helpers. We are not blocking on this β template-engine keeps its local implementation for now and will migrate when this lands.
π€ Generated with Claude Code
Feature Request ποΈ
Provide first-class helpers on the model API to answer "is type X, or does it extend, type Y?" and "what concrete types are assignable to Y?" β without each consumer re-implementing the traversal over
getAssignableClassDeclarations().Use Case
Consumers frequently need to test the runtime/nominal class hierarchy of a model:
fqna subtype of (or equal to)baseFqn?" β e.g. validating that a payload's$classis, or extends, a known base type.baseFqn?" β e.g. building a union/enumeration of valid subtypes (plus the base itself when it is concrete).Today the building blocks exist (
ClassDeclaration.getAssignableClassDeclarations(),getAllSuperTypeDeclarations(),isAbstract()), but there is no concise, discoverable helper for these two very common questions. The onlyModelUtil.isAssignableTo(modelFile, typeName, property)is@privateand answers a different question (can a type be assigned to a property), so it can't be reused for a plain subtype check.Possible Solution
Expose two small, pure helpers (on
ModelUtil,ModelManager, or a new introspection util β wherever fits best):isAssignableTocan be implemented in terms ofgetAssignableConcreteTypes(membership test), or more directly by walkinggetAllSuperTypeDeclarations()from the candidate β implementer's choice. Naming is a suggestion; happy to align with existing conventions (note the@privateModelUtil.isAssignableToname clash to disambiguate).Context
In accordproject/template-engine#166 we enforce a runtime class hierarchy (State / Request / Response / Event) both at compile time (building a TypeScript union of the assignable concrete types) and at runtime (checking a payload's
$classis-a the base). We implemented these two helpers locally in the template-engine's ownutils.tsand had two call sites drift apart during review before centralizing them β a reviewer specifically flagged that the assignability rule should have a single source of truth. This felt like model-level functionality that belongs in Concerto rather than being re-derived by each downstream project.Detailed Description
false).π€ Generated with Claude Code