transformutils

package
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 5, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// AnnotationSourceAbstractName is the annotation key set by transformer plugins
	// to record the original abstract resource name that a concrete resource was
	// expanded from.
	AnnotationSourceAbstractName = "bluelink.transform.source.abstractName"

	// AnnotationSourceAbstractType is the annotation key set by transformer plugins
	// to record the original abstract resource type that a concrete resource was
	// expanded from.
	AnnotationSourceAbstractType = "bluelink.transform.source.abstractType"

	// AnnotationResourceCategory is the annotation key set by transformer plugins
	// to classify a concrete resource as either "code-hosting" or "infrastructure".
	// Used by the code-only auto-approval mechanism.
	AnnotationResourceCategory = "bluelink.transform.resourceCategory"

	// ResourceCategoryCodeHosting indicates a resource that hosts application code
	// (e.g. Lambda function, ECS task, API Gateway).
	ResourceCategoryCodeHosting = "code-hosting"

	// ResourceCategoryInfrastructure indicates an infrastructure dependency
	// (e.g. DynamoDB table, S3 bucket, IAM role, VPC).
	ResourceCategoryInfrastructure = "infrastructure"
)

Variables

This section is empty.

Functions

func Field

Field is sugar for a literal field-name path item:

&SubstitutionPathItem{FieldName: name}.

func Index

Index is sugar for a literal array-index path item:

&SubstitutionPathItem{ArrayIndex: &index}.

func MakeRef

func MakeRef(
	newResourceName string,
	path []*substitutions.SubstitutionPathItem,
) *substitutions.Substitution

MakeRef is a low-level constructor that builds a SubstitutionResourceProperty pointing at newResourceName with the given path. The caller assembles the path explicitly from Field / Index items and (where useful) slices of ref.Path. Used for cases that don't fit RewriteFields' 1:1 model.

func PathExact

func PathExact(
	ref *substitutions.SubstitutionResourceProperty,
	fieldPathSegments ...string,
) bool

PathExact returns true if the ref's path matches the given field names exactly (ignoring array indices between field names).

func PathMatches

func PathMatches(
	ref *substitutions.SubstitutionResourceProperty,
	fieldPathSegments ...string,
) bool

PathMatches returns true if the ref's path starts with the given field path segments, ignoring array indices. Useful for prefix matching on nested structures.

For example:

ref: spec.vpc.securityGroups[0].id
fieldPathSegments: "spec", "vpc", "securityGroups"
returns: true (matches the prefix of the path, ignoring indices)

func RegisterEmit

func RegisterEmit[T any, PR ResolvedPtr[T]](
	reg *TransformerRegistry,
	target Target,
	fn func(r PR, resPropRewriter ResourcePropertyRewriter, transformCtx transform.Context) (*EmitResult, error),
)

RegisterEmit is a generic helper to register an emitter for a specific target, ensuring type safety on the resolved type.

The registry is keyed by the pointer type *T (PR), not the value type T, because aggregators put *T values into EmitPlan.Primaries — so reflect.TypeOf(primary) at emit-lookup time is the pointer type, and the registration key must match.

func RegisterRewriter

func RegisterRewriter[T any, PR ResolvedPtr[T]](
	reg *TransformerRegistry,
	target Target,
	fn func(r PR) []ResourcePropertyRewriter,
)

RegisterRewriter is a generic helper to register a rewrite factory for a specific target, ensuring type safety on the resolved type. Keyed by *T (PR) for the same reason as RegisterEmit — primaries are pointer-typed at lookup time.

func RetargetRef

func RetargetRef(
	ref *substitutions.SubstitutionResourceProperty,
	newResourceName string,
) *substitutions.Substitution

RetargetRef returns a SubstitutionResourceProperty identical to ref but pointing at newResourceName. The path (including array indices) is preserved. Use when only the resource name changes.

func RewriteBlueprintRefs

func RewriteBlueprintRefs(
	blueprint *schema.Blueprint,
	visitor subwalk.SubstitutionVisitor,
) *schema.Blueprint

RewriteBlueprintRefs returns a shallow copy of blueprint with every substitution-bearing top-level section walked by visitor. Sections walked:

  • Exports[*] — every value (direct field reference, not in ${..}) and description StringOrSubstitutions
  • Values[*] — every value and description StringOrSubstitutions
  • Include[*] — path, variables, metadata, description
  • DataSources[*] — filter search values, metadata, description
  • Metadata — top-level free-form mapping

Sections passed through unchanged (no substitution support as per spec):

  • Variables, Version

Resources and Transform are also passed through here; the transformer owns those separately:

  • Resources: spec-level rewrites happen inline during per-resource emit, where each emitter has access to resource-specific structural transformations (memory -> memorySize, etc.). The driver replaces this section wholesale with emitted output.
  • Transform: the transformer strips its own identifier from this list.

Returns a shallow copy — the input blueprint is not mutated, but pointer-shared sub-trees that weren't rewritten remain shared.

func RewriteFields

func RewriteFields(
	ref *substitutions.SubstitutionResourceProperty,
	newResourceName string,
	newFields ...string,
) *substitutions.Substitution

RewriteFields is a declarative high-level helper to be used by transformers when rewriting references to resource properties.

It can rename fields in ref.Path one-to-one, with N-dimensional array indices auto-preserved at their original relative positions. The i-th field-name item in ref.Path becomes newFields[i]; index items sandwiched between fields are kept at the same relative slot (between the renamed fields they followed). Source items beyond len(newFields) field positions are appended unchanged.

Examples (paths shown logically; "[i]" stands for any source array index):

.spec.memory                  -> .spec.memorySize
    newFields = "spec", "memorySize"
.spec.routes[i].method        -> .spec.paths[i].httpMethod
    newFields = "spec", "paths", "httpMethod"     (one-dimensional)
.spec.rules[i].targets[j].arn -> .spec.rules[i].destinations[j].arn
    newFields = "spec", "rules", "destinations", "arn"   (two-dimensional)

Extra field names beyond the original path are appended. Use MakeRef when the rewrite needs to insert or remove fields, restructure nesting depth (e.g. environmentVariables -> environment.variables), or introduce literal array indices that don't exist in the source path.

func RewriteResourcePropertyRefs

func RewriteResourcePropertyRefs(rewriter ResourcePropertyRewriter) subwalk.SubstitutionVisitor

RewriteResourcePropertyRefs builds a SubstitutionVisitor from a ResourcePropertyRewriter. Only SubstitutionResourceProperty substitutions are passed to the rewriter; all other substitution types pass through.

func RunTransformPipeline

func RunTransformPipeline(
	inputBlueprint *schema.Blueprint,
	linkGraph linktypes.DeclaredLinkGraph,
	target Target,
	transformerID string,
	registry *TransformerRegistry,
	transformCtx transform.Context,
) (*transform.SpecTransformerTransformOutput, error)

RunTransformPipeline drives the framework's transformer pipeline for plugins that don't provide their own TransformFunc implementation.

func TransformerBaseAnnotations

func TransformerBaseAnnotations(
	input *TransformerBaseAnnotationsInput,
) *schema.StringOrSubstitutionsMap

TransformerBaseAnnotations returns base annotations to be used for concrete resources generated from an abstract resource type to maintain correlation between the abstract resource in your blueprint and the concrete resources that will be deployed.

func ValueRef

func ValueRef(
	valueName string,
	path ...*substitutions.SubstitutionPathItem,
) *substitutions.Substitution

ValueRef returns a SubstitutionValueReference. With no path items it is the flat form ${values.<name>}; trailing path items target a nested field or array element when the transformer-generated value is a complex object or list. Path items are built with Field / Index, identical to resource refs.

Examples:

ValueRef("ordersHandler_lambda_arn")
    -> ${values.ordersHandler_lambda_arn}
ValueRef("ordersDb_connection", Field("host"))
    -> ${values.ordersDb_connection.host}
ValueRef("api_endpoints", Index(0), Field("url"))
    -> ${values.api_endpoints[0].url}

Types

type Aggregator

type Aggregator func([]ResolvedResource) *EmitPlan

Aggregator is a function that produces an emit plan from a list of resources resolved for a particular abstract resource type.

type Capabilities

type Capabilities struct {
	// SupportedAbstractPaths is the set of dot notation abstract
	// property paths this (target, resource-type) pair handles.
	// This is generated from a PropertyMap.
	SupportedAbstractPaths []string
}

func CapabilitiesFromPropertyMap

func CapabilitiesFromPropertyMap(pm *PropertyMap) *Capabilities

CapabilitiesFromPropertyMap derives a Capabilities struct from a property map's rename and value reference paths.

type EmitPlan

type EmitPlan struct {
	// Primaries are the main resolved resources that will be emitted as concrete output.
	Primaries []ResolvedResource
	// SharedParents allow aggregates to declare concrete output resources
	// that don't correspond to any single abstract input.
	// This lets  pre-primary emits populate shared parents incrementally so
	// partial-fold targets (e.g. Azure Function, Cloud Run, VPC Connector)
	// can produce per-resource outputs and shared resource output in the same
	// pass without giving up the the per-primary 1:1 mapping that a full fold
	// implementation would otherwise require.
	SharedParents []SharedParent
}

EmitPlan represents the output of the aggregation phase that is fed into the concrete output emission phase.

type EmitResult

type EmitResult struct {
	Resources     map[string]*schema.Resource
	DerivedValues map[string]*schema.Value
	// Mapping of shared parent key to the contributions
	// from all resources that share this parent.
	SharedParentContributions map[string]*core.MappingNode
	Diagnostics               []*core.Diagnostic
}

EmitResult represents the output of the emission phase for a single resolved resource.

type Emitter

type Emitter func(
	r ResolvedResource,
	resPropRewriter ResourcePropertyRewriter,
	transformCtx transform.Context,
) (*EmitResult, error)

Emitter produces concrete output for one resolved primary for a specific target.

type EmitterRegistration

type EmitterRegistration func(registry *TransformerRegistry, t Target)

EmitterRegistration is a deferred registration closure that captures the concrete resolved type. This is necessary to allow authors to write their emitters with concrete resolved types while maintaing a valid homogenous map value type for emitter storage in registries.

func TypedEmitter

func TypedEmitter[T any, PR ResolvedPtr[T]](
	fn func(
		r PR,
		resPropRewriter ResourcePropertyRewriter,
		transformCtx transform.Context,
	) (*EmitResult, error),
) EmitterRegistration

TypedEmitter is a generic helper to produce an EmitterRegistration for a specific target, ensuring type safety on the resolved type. This is intended for use in AbstractResourceDefinition.Emitters maps.

type PropertyMap

type PropertyMap struct {
	// Renames contains simple 1:1 mappings of abstract property name to concrete property name.
	// The key is a dotted abstract path and value consists of concrete path
	// segments. Array indices in the abstract path are auto-preserved at their
	// original positions (RewriteFields semantics).
	Renames map[string][]string

	// ValueRefs contains mappings of abstract refs that should redirect to
	// a transformer-derived value. For example, a composite abstract value
	// derived from multiple concrete resource properties.
	// The key is a dotted abstract path and values describe the value reference.
	ValueRefs map[string]*ValueRefSpec

	// Custom contains custom rules that don't fit into the rename
	// or value-ref categories.
	Custom []*PropertyRule
}

PropertyMap is a declarative description of how an abstract resource's substitution-referenceable properties map to a target's concrete equivalents. The majority of cases will be 1:1 renames and value-ref redirects; a small number of cases will involve structural reshapes or literal index injections.

func (*PropertyMap) Rewriter

func (pm *PropertyMap) Rewriter(abstractName, concreteName string) ResourcePropertyRewriter

Rewriter materialises the PropertyMap as a ResourcePropertyRewriter closure parameterised with the abstract ↔ concrete name pair from one resolved primary.

Renames / ValueRefs key splits and Custom MatchPaths patterns are pre-compiled once per closure so per-ref dispatch is O(rules) without repeated string parsing.

type PropertyRule

type PropertyRule struct {
	// MatchPaths is the path-pattern set this rule handles.
	// Patterns may contain "[*]" to match an array index (e.g. "spec.vpc.securityGroups[*].id").
	// MatchPaths is the single source of truth for both runtime matching and capabilitiy extraction.
	MatchPaths []string

	// Predicate is an optional further filter beyond the path match.
	// Most rules will only need match paths and leave this as nil.
	// When defined, the rule applies only if the substitution's path
	// matches one of MatchPaths AND Predicate returns true.
	// Predicate-conditional matches are intentionally outside the capabilities
	// scope (capabilities are purely path-based); document conditional
	// behaviour via abstract resource or link definitions for users and your
	// own developer guidance for future maintainers.
	Predicate func(*substitutions.SubstitutionResourceProperty) bool

	// Rewrite produces the new substitution if the rule matches.
	Rewrite func(
		ref *substitutions.SubstitutionResourceProperty,
		rewriteCtx RewriteContext,
	) *substitutions.Substitution
}

PropertyRule describes a custom rule for rewriting a resource property reference that doesn't fit into the rename or value-ref categories. The Match function determines whether the rule applies to a given reference, and the Rewrite function produces the new substitution if it does.

type ResolvedPtr

type ResolvedPtr[T any] interface {
	*T
	ResolvedResource
}

ResolvedPtr is a generic helper interface to ensure type safety on resolved resource types. Concrete resolved types implement ResolvedResource with pointer receivers, so the constraint is expressed via ResolvedPtr[T]; "PR is *T and *T satisfies ResolvedResource".

type ResolvedResource

type ResolvedResource interface {
	ResourceName() string
	ResourceType() string
}

ResolvedResource is the target-agnostic output of the resolve phase that is fed into aggregation, rewriting and emission. Concrete resource types (e.g. *ResolvedQueue, *ResolvedHandler) live in their resource packages and implement this interface.

type Resolver

type Resolver func(
	name string,
	resource *schema.Resource,
	linkGraph linktypes.DeclaredLinkGraph,
	blueprint *schema.Blueprint,
) (ResolvedResource, error)

Resolver is a target-agnostic resolver for a single abstract resource type. These resolvers are keyed by abstract resource type in a transformer registry and are not tied to any specific target.

type ResourcePropertyRewriter

type ResourcePropertyRewriter func(
	ref *substitutions.SubstitutionResourceProperty,
) *substitutions.Substitution

ResourcePropertyRewriter is called for each SubstitutionResourceProperty found during traversal. It receives the full SubstitutionResourceProperty (resource name, property path at any depth, template index) and returns: - A replacement *Substitution (any variant: resource ref, value ref, etc.) - nil to keep the original unchanged

func ChainResourcePropertyRewriters

func ChainResourcePropertyRewriters(
	rewriters ...ResourcePropertyRewriter,
) ResourcePropertyRewriter

ChainResourcePropertyRewriters combines multiple rewriters into one. The first rewriter to return a non-nil substitution wins.

type RewriteContext

type RewriteContext struct {
	AbstractName string
	ConcreteName string
}

RewriteContext provides contextual information for custom property rewrite rules.

type RewriteFactory

type RewriteFactory func(r ResolvedResource) []ResourcePropertyRewriter

RewriteFactory produces a list of rewriters from on resolved primary. Returns multiple for compound primaries (e.g. a ResolvedService folding in N handlers + M apis, contributes to N+M rewriters).

type RewriterRegistration

type RewriterRegistration func(registry *TransformerRegistry, t Target)

RewriterRegistration is a deferred registration closure that captures the concrete resolved type for rewriters. This is necessary to allow authors to write their rewriters with concrete resolved types while maintaing a valid homogenous map value type for rewriter storage in registries.

func RewriterFromPropertyMap

func RewriterFromPropertyMap[T any, PR ResolvedPtr[T]](
	pm *PropertyMap,
	concreteName func(r PR) string,
) RewriterRegistration

RewriterFromPropertyMap produces a RewriterRegistration that wraps a PropertyMap in a single-rewriter factory. The concreteName function derives the concrete resource name for one resolved primary; this is the per-target piece of information that the PropertyMap itself can't carry (different targets name the same abstract resource differently — _sqs, _lambda, _topic, etc.).

Side effect: also registers a capability-matrix entry for (target, *T) derived from the same PropertyMap, so pre-emit reference validation and authoring docs see the supported abstract paths without authors having to do anything else. The capability matrix and the rewriter share the same PropertyMap as a single source of truth.

Use this as the typical declarative path for AbstractResourceDefinition.Rewriters when the rewriting is fully described by a PropertyMap. For compound primaries or multi-rewriter contributions, use TypedRewriter with a hand-written factory instead — capability matrix entries for those cases must be supplied via the Registry overlay.

func TypedRewriter

func TypedRewriter[T any, PR ResolvedPtr[T]](
	fn func(r PR) []ResourcePropertyRewriter,
) RewriterRegistration

TypedRewriter is a generic helper to produce a RewriterRegistration for a specific target, ensuring type safety on the resolved type. This is intended for use in AbstractResourceDefinition.Rewriters maps.

type SharedParent

type SharedParent struct {
	Key          string
	ResourceName string
	ResourceType string
	Annotations  *core.MappingNode
	SeedSpec     *core.MappingNode
}

SharedParent represents a declared concrete output resource that doesn't correspond to a single abstract input resource.

type Target

type Target string

Target represents a deployment target such as "aws-serverless" or "azure".

type TransformerBaseAnnotationsInput

type TransformerBaseAnnotationsInput struct {
	// AbstractResourceName is the name of the abstract resource in the blueprint.
	AbstractResourceName string
	// AbstractResourceType is the type of the abstract resource in the blueprint.
	AbstractResourceType string
	// ResourceCategory is the category of the resource, either "code-hosting" or "infrastructure".
	ResourceCategory string
}

type TransformerRegistry

type TransformerRegistry struct {
	// contains filtered or unexported fields
}

func NewTransformerRegistry

func NewTransformerRegistry() *TransformerRegistry

func (*TransformerRegistry) AggregatorFor

func (r *TransformerRegistry) AggregatorFor(target Target) (Aggregator, bool)

AggregatorFor looks up the aggregator for a given target.

func (*TransformerRegistry) CapabilitiesFor

func (r *TransformerRegistry) CapabilitiesFor(
	target Target,
	resolvedType reflect.Type,
) (Capabilities, bool)

CapabilitiesFor looks up the capability matrix entry for a given target and resolved resource type. Used by pre-emit reference validation (Pillar 4) and tooling that renders authoring docs.

func (*TransformerRegistry) EmitterFor

func (r *TransformerRegistry) EmitterFor(
	target Target,
	resolvedType reflect.Type,
) (Emitter, bool)

EmitterFor looks up the emitter for a given target and resolved resource type.

func (*TransformerRegistry) HasAggregators

func (r *TransformerRegistry) HasAggregators() bool

HasAggregators reports whether the registry has at least one aggregator registered. Used by the framework's first-use validation to confirm that a pipeline-mode plugin has at least one aggregator across the union of TransformerPluginDefinition.Aggregators and the Registry overlay.

func (*TransformerRegistry) IsEmpty

func (r *TransformerRegistry) IsEmpty() bool

IsEmpty reports whether the registry holds zero registrations across all dimensions (resolvers, aggregators, emitters, rewriters, capabilities). Used by the framework to decide whether a non-nil overlay registry actually contributes anything to the pipeline-detection signal.

func (*TransformerRegistry) MergeFrom

func (r *TransformerRegistry) MergeFrom(other *TransformerRegistry)

MergeFrom merges every registration from other into r. Collisions on any dimension (resolver abstract type, aggregator target, (target, resolved- type) emitter / rewriter / capability) panic with a "duplicate registration" message — this matches the original design's "Registry overlay collides with auto-derived registration" contract and keeps misconfig loud rather than silently overwriting one source with another.

A nil receiver panics; a nil other is a no-op.

func (*TransformerRegistry) RegisterAggregator

func (r *TransformerRegistry) RegisterAggregator(
	target Target,
	aggregator Aggregator,
)

RegisterAggregator registers an aggregator function for a given deployment target.

func (*TransformerRegistry) RegisterResolver

func (r *TransformerRegistry) RegisterResolver(
	abstractResourceType string,
	resolver Resolver,
)

RegisterResolver registers a resolver function for a given abstract resource type.

func (*TransformerRegistry) ResolverFor

func (r *TransformerRegistry) ResolverFor(abstractResourceType string) (Resolver, bool)

ResolverFor looks up the resolver for a given abstract resource type.

func (*TransformerRegistry) RewriteFactoryFor

func (r *TransformerRegistry) RewriteFactoryFor(
	target Target,
	resolvedType reflect.Type,
) (RewriteFactory, bool)

RewriteFactoryFor looks up the rewrite factory for a given target and resolved resource type.

type ValueRefSpec

type ValueRefSpec struct {
	// Suffix appended to the concrete resource name to form the value name.
	// e.g. "_arn" -> ${values.<concreteName>_arn}
	Suffix string
	// Path is for complex derived values (e.g. {url, authType} objects).
	// The path descends into the value. Empty path is a flat ref.
	Path []*substitutions.SubstitutionPathItem
}

ValueRefSpec describes how to construct a value reference for a property that doesn't have a simple 1:1 mapping to a concrete resource property.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL