Field Transformation Code Generation
Produces ready-to-use C# code files for the Migration.Tool.Extensions project. Takes the migration plan output from the migrate-content-plan skill — or a direct text description — as input.
Workflow
Step 1: Read Reference Materials
- Read
references/field-migration-api.mdfor the complete API patterns and decision guides. - If you need pattern examples for implementation, read
assets/FIELD_MIGRATION_EXAMPLE.csfor a complete annotated reference implementation. - If you need context on the migration tool's extension points or configuration, read
../_shared/references/migration-tool.md. - If you need documentation links for the Kentico Migration Tool, read
../_shared/references/migration-docs.md. - If a Kentico documentation lookup tool is available, use it for additional context on XbyK form components, data types, or the Migration Tool API.
Step 2: Analyze Input
- If a migration plan file path is provided → read it and extract from the Field Mappings section: Field Changes tables (scan for data type or form control changes), Custom Form Control Fields table (lists fields with non-built-in form controls and their handling mechanisms), and Custom Value Transforms table.
- If the migration plan has no Custom Form Control Fields section, scan the Field Changes tables for any field with a data type change or form control change column that is not handled by a built-in mapping or
WithFieldPatchin anIClassMapping. These are candidates forIFieldMigrationcode orappsettings.jsonFieldMigrationsconfig. - If a direct text description is provided → identify source form controls, data types, field names, and transformation needs.
- Ask clarifying questions if the transformation logic, target form components, or scope (which classes) are ambiguous.
Step 3: Identify Migrations to Generate
Determine the set of IFieldMigration classes needed:
- One
IFieldMigrationclass per logical transformation concern (e.g., one for custom rich text editors, one for HTML cleanup, one for date format conversion). - Group related form controls or data types into a single migration when they share the same transformation logic.
- One
ServiceCollectionExtensionsclass for DI registration. - Cross-reference the built-in mapping table in
../_shared/references/migration-tool.md— the migration tool has defaultFieldMigrationentries for standard data type + form control combinations (e.g.,text + TextBoxControl → TextInput,longtext + HtmlAreaControl → RichTextEditor). It also has catch-all entries per data type (e.g.,text + _other_ → TextInput,longtext + _other_ → TextArea). If a source form control matches a built-in entry or catch-all AND the target data type doesn't change, noIFieldMigrationis needed. - Check for data type changes: Built-in catch-all mappings preserve the source data type — they do not change it. If a field requires a data type change (e.g.,
text → longtext) AND a form control change, the catch-all won't produce the correct result. UseIFieldMigrationcode,appsettings.jsonFieldMigrationsconfig, orIClassMapping.WithFieldPatchinstead. - Check the migration plan's Custom Form Control Fields section (if present) — fields marked with handling mechanism "IFieldMigration code" need code generation. Fields marked "Built-in catch-all", "FieldMigrations config", or "WithFieldPatch" do not.
- Skip code generation for:
- Simple form control swaps with no value change → use
appsettings.jsonFieldMigrationsconfig instead. - Field renames or per-class value transforms → use
IClassMappingSetFrom/ConvertFrominstead. - Field definition changes scoped to a single class → consider
IClassMapping.WithFieldPatchinstead. - Built-in conversions already handled by the migration tool defaults (including catch-all entries).
- Simple form control swaps with no value change → use
- Recommend
IClassMapping.ConvertFromwhen the transform is specific to one class and one field (per-class scope, not cross-class). - Recommend
IClassMapping.WithFieldPatchwhen the field definition change (data type, form component) is scoped to a single class and paired with anIClassMappingthat already exists for that class.
Step 4: Generate Field Migration Code
For each migration, generate a class implementing IFieldMigration:
Rank— use values < 100,000 (built-in defaults use 100,000+). Leave gaps between values (1000, 2000, 3000) for future insertions.ShallMigrate— precise matching onSourceFormControl,SourceDataType,FieldName, orClassName. Avoid overly broad matches that interfere with built-in migrations.MigrateFieldDefinition— useSystem.Xml.LinqXElement API to patch XML field definitions (controlname, column type, data type, settings).MigrateValue— null-safe (null or DBNullcheck), type-safe (is string spattern), context-aware (SourceObjectContextswitch when behavior differs).- Include a per-migration
IServiceCollectionextension method for DI registration.
Step 5: Generate Service Registration
Generate or update the ServiceCollectionExtensions static class:
- Call each migration's extension method.
AddSingleton<IFieldMigration>(new T())for each migration.- Include comment noting that fields handled by
IFieldMigrationcode do not need entries inappsettings.jsonFieldMigrationsconfig. - Include comment noting any prerequisite appsettings or
IClassMappingregistrations.
Step 6: Build Verification
- Build the
Migration.Tool.Extensionsproject to verify the generated code compiles without errors. - If the build fails, analyze the error messages, fix all issues in the generated code, and rebuild.
- Repeat up to 3 attempts. If the build still fails after 3 attempts, present the full build output and error details to the user for manual resolution.
Step 7: Present and Refine
Save files to the user-specified path (default:
Migration.Tool.Extensions/FieldMigrations/— generated code belongs in theMigration.Tool.Extensionsproject, matching theMigration.Tool.Extensions.FieldMigrationsnamespace).Provide a summary table of generated migrations:
File Pattern Rank Handles CommunityTextEditorFieldMigration.csForm control replacement 1000 CommunityTextEditor → RichTextEditor DateTextFieldMigration.csData type conversion 2000 EventDateText text → datetime Ask if any migrations need adjustment and iterate on feedback.
Rules
- Namespace:
Migration.Tool.Extensions.FieldMigrations(user can override). - File naming:
{DescriptiveName}FieldMigration.cs. - Use string constants for source/target form control names and data types, following the
Source_/Target_prefix convention from the example. - Add
TODOcomments for values unknown at generation time (e.g., target asset paths, lookup dictionaries). - Follow exact API patterns from
field-migration-api.md— do not invent methods that don't exist. - Every
IFieldMigrationmust have a correspondingAddSingleton<IFieldMigration>(new T())registration. - Handle both structured (migration plan) and free-text input.
MigrateFieldDefinitionusesSystem.Xml.LinqXElement API — find or create elements, set values, remove obsolete settings.MigrateValuemust handle null (null or DBNull) and unexpected types defensively.- Prefer
IClassMapping.ConvertFromfor class-specific, per-field transforms; useIFieldMigrationfor cross-class or form-control-driven transforms. - If a Kentico documentation lookup tool is available, verify uncertain API details before generating code.
- After generating code, always build the project and fix compilation errors before considering the task complete.
Gotchas
ShallMigrateis called for every field in every class — must be lightweight and specific. Broad matching (e.g., all"text"fields) interferes with built-in migrations.MigrateFieldDefinitionandMigrateValuemust be aligned — if the definition changes the data type, the value must be converted to match.- Custom rank values must be < 100,000 (built-in defaults use 100,000+; lower rank = higher priority).
- Fields handled by
IFieldMigrationdo NOT needappsettings.jsonFieldMigrationsentries. Skip code generation when config suffices (simple form control swap, no value transform). - When a field definition change is scoped to a single class that already has an
IClassMapping, preferWithFieldPatchoverIFieldMigration— it keeps the definition change co-located with the class mapping. Only useIFieldMigrationwhen the same form control or data type change applies across multiple classes. - Check
SourceObjectContextwhen transformation behavior differs across pages, custom tables, and forms. - This skill generates
IFieldMigrationcode only —IClassMapping,ContentItemDirectorBase,IWidgetMigration, andIWidgetPropertyMigrationare separate extension points.