Introduce typed D&D spell artifacts

This commit is contained in:
2026-07-17 06:50:08 +00:00
parent b949e9bbc0
commit 142ba36695
27 changed files with 836 additions and 608 deletions

View File

@@ -23,6 +23,7 @@ type typedExtractorEntry struct {
valueType reflect.Type
validateOptions OptionValidator
builder func(BuildRequest) (any, error)
rawBuilder LegacyRawExtractorBuilder
}
func NewExtractorRegistry() *ExtractorRegistry {
@@ -92,6 +93,20 @@ func RegisterExtractor[T any](registry *ExtractorRegistry, spec ModuleSpec, cons
}
func RegisterExtractorBuilder[T any](registry *ExtractorRegistry, spec ModuleSpec, validateOptions OptionValidator, builder func(BuildRequest) (contracts.Extractor[T], error)) error {
return registerExtractorBuilder(registry, spec, validateOptions, builder, nil)
}
// RegisterExtractorBuilderWithRawAdapter registers a typed extractor while a
// raw downstream remains in use. Resolution selects the adapter until the
// registration is replaced with the typed-only builder.
func RegisterExtractorBuilderWithRawAdapter[T any](registry *ExtractorRegistry, spec ModuleSpec, validateOptions OptionValidator, builder func(BuildRequest) (contracts.Extractor[T], error), rawBuilder LegacyRawExtractorBuilder) error {
if rawBuilder == nil {
return fmt.Errorf("extractor raw adapter builder for %q must not be nil", strings.TrimSpace(spec.Key))
}
return registerExtractorBuilder(registry, spec, validateOptions, builder, rawBuilder)
}
func registerExtractorBuilder[T any](registry *ExtractorRegistry, spec ModuleSpec, validateOptions OptionValidator, builder func(BuildRequest) (contracts.Extractor[T], error), rawBuilder LegacyRawExtractorBuilder) error {
if registry == nil {
return fmt.Errorf("extractor registry must not be nil")
}
@@ -118,6 +133,7 @@ func RegisterExtractorBuilder[T any](registry *ExtractorRegistry, spec ModuleSpe
builder: func(request BuildRequest) (any, error) {
return builder(cloneBuildRequest(request))
},
rawBuilder: rawBuilder,
}
if registry.typedEntries == nil {
registry.typedEntries = make(map[string]typedExtractorEntry)
@@ -143,6 +159,12 @@ func (r *ExtractorRegistry) BuildLegacyRawWithRequest(key string, request BuildR
return nil, fmt.Errorf("extractor key must not be empty")
}
builder, ok := r.legacyBuilders[normalizedKey]
if !ok {
if entry, typedOK := r.typedEntries[normalizedKey]; typedOK && entry.rawBuilder != nil {
builder = entry.rawBuilder
ok = true
}
}
if !ok {
return nil, fmt.Errorf("legacy raw extractor %q is not registered", normalizedKey)
}
@@ -193,6 +215,11 @@ func (r *ExtractorRegistry) typedEntry(key string) (typedExtractorEntry, bool) {
return entry, ok
}
func (r *ExtractorRegistry) usesRawAdapter(key string) bool {
entry, ok := r.typedEntry(key)
return ok && entry.rawBuilder != nil
}
func (r *ExtractorRegistry) RegisteredKeys() []string {
if r == nil {
return nil