Skip to main content

Built-in Transforms

The FDS Transformer includes a set of built-in transform functions for common data manipulation tasks. These can be used in the transform property of field mappings.

Transform Reference

slugify

Convert a string to a URL-safe slug.

Input: String
Output: String

{
"canonical.slug": {
"from": "name",
"transform": "slugify"
}
}

Examples:

InputOutput
"Barbell Bench Press""barbell-bench-press"
"Cable Fly (Low)""cable-fly-low"
"Push-Up""push-up"

Behavior:

  • Converts to lowercase
  • Replaces spaces with hyphens
  • Removes special characters
  • Collapses multiple hyphens

titleCase

Convert a string to Title Case.

Input: String
Output: String

{
"canonical.name": {
"from": "name",
"transform": "titleCase"
}
}

Examples:

InputOutput
"barbell bench press""Barbell Bench Press"
"DEADLIFT""Deadlift"
"push-up""Push-Up"

uuid

Generate a UUIDv4 string. FDS requires plain UUIDs for all identifiers.

Input: Any (ignored)
Output: String

{
"exerciseId": {
"from": null,
"transform": "uuid"
}
}

Example Output: "550e8400-e29b-41d4-a716-446655440000"


toArray

Ensure a value is wrapped in an array.

Input: Any
Output: Array

{
"targets.primary": {
"from": "target",
"transform": "toArray"
}
}

Examples:

InputOutput
"chest"["chest"]
["chest", "shoulders"]["chest", "shoulders"]
null[]

toMediaArray

Convert URLs to FDS media format.

Input: String, Array of strings, or Array of objects
Output: Array of MediaItem objects

Options:

OptionTypeDefaultDescription
defaultTypestring"image"Default media type
inferTypebooleantrueInfer type from file extension
{
"media": {
"from": "images",
"transform": "toMediaArray",
"options": {
"defaultType": "image",
"inferType": true
}
}
}

Input:

["https://example.com/bench-press.jpg", "https://example.com/video.mp4"]

Output:

[
{ "type": "image", "uri": "https://example.com/bench-press.jpg" },
{ "type": "video", "uri": "https://example.com/video.mp4" }
]

Type Inference:

ExtensionType
.jpg, .jpeg, .png, .gif, .webp, .svgimage
.mp4, .webm, .mov, .avivideo
.pdf, .md, .txtdoc
.glb, .gltf, .obj3d

registryLookup

Look up a value in a registry with optional fuzzy matching.

Input: String or Array
Output: Object or Array of objects

Options:

OptionTypeDefaultDescription
registrystringRequiredRegistry name: muscles, equipment, muscleCategories
fuzzyMatchbooleanfalseEnable fuzzy matching
thresholdnumber0.8Fuzzy match threshold (0-1)
fieldstring"canonical.name"Field to match against
returnFormatstring"object"Return format: object, array, ref
includeAliasesbooleantrueInclude aliases in matching
{
"targets.primary": {
"from": "target",
"transform": "registryLookup",
"options": {
"registry": "muscles",
"fuzzyMatch": true,
"threshold": 0.8,
"returnFormat": "array"
}
}
}

Input: "pectorals"

Output:

[
{
"id": "mus.pectoralis-major",
"name": "Pectoralis Major",
"slug": "pectoralis-major",
"categoryId": "cat.chest"
}
]

Return Formats:

  • object - Full registry entry
  • array - Wrapped in array
  • ref - FDS reference format ({ id, name, slug, categoryId })

timestamp

Generate an ISO 8601 timestamp.

Input: Any (ignored)
Output: String

{
"metadata.createdAt": {
"from": null,
"transform": "timestamp"
}
}

Example Output: "2025-01-27T15:30:00.000Z"


autoGenerate

Auto-generate metadata fields.

Input: Any (ignored)
Output: Object

Options:

OptionTypeDefaultDescription
fieldsstring[]All fieldsFields to generate
{
"metadata": {
"from": null,
"transform": "autoGenerate",
"options": {
"fields": ["createdAt", "updatedAt", "status"]
}
}
}

Output:

{
"createdAt": "2025-01-27T15:30:00.000Z",
"updatedAt": "2025-01-27T15:30:00.000Z",
"status": "active"
}

Available Fields:

FieldGenerated Value
createdAtCurrent ISO timestamp
updatedAtCurrent ISO timestamp
status"active"
version"1.0.0"
source"fds-transformer"

template

Apply a template string with variable substitution.

Input: Object (context)
Output: String

Options:

OptionTypeRequiredDescription
templatestringYesTemplate string with {{field}} placeholders
defaultValuestringNoDefault for missing fields
{
"canonical.description": {
"from": ["name", "target", "equipment"],
"transform": "template",
"options": {
"template": "{{name}} is an exercise targeting the {{target}} using {{equipment}}."
}
}
}

Context:

{
"name": "Barbell Bench Press",
"target": "chest",
"equipment": "barbell"
}

Output: "Barbell Bench Press is an exercise targeting the chest using barbell."


urlTransform

Transform URLs with pattern matching.

Input: String (URL)
Output: String

Options:

OptionTypeDescription
patternstringRegex pattern to match
replacementstringReplacement string
prefixstringPrefix to add
suffixstringSuffix to add
{
"media[0].uri": {
"from": "imageUrl",
"transform": "urlTransform",
"options": {
"pattern": "http://",
"replacement": "https://"
}
}
}

Input: "http://example.com/image.jpg"
Output: "https://example.com/image.jpg"


Chaining Transforms

Apply multiple transforms in sequence:

{
"canonical.slug": {
"from": "name",
"transform": ["titleCase", "slugify"]
}
}

Transforms are applied left to right. The output of each transform becomes the input of the next.

Example:

  1. Input: "barbell BENCH press"
  2. After titleCase: "Barbell Bench Press"
  3. After slugify: "barbell-bench-press"

Using with Registry Lookup

Common pattern for muscle/equipment mapping:

{
"targets.primary": {
"from": "target",
"transform": ["toArray", "registryLookup"],
"options": {
"registry": "muscles",
"fuzzyMatch": true,
"returnFormat": "ref"
}
}
}

This:

  1. Wraps the value in an array if needed
  2. Looks up each value in the muscles registry
  3. Returns FDS reference format

Transform Context

All transforms receive a context object with:

interface TransformContext {
source: Record<string, unknown>; // Original source data
target: Record<string, unknown>; // Current FDS object being built
field: string; // Current field path
registries: {
muscles: RegistryEntry[];
equipment: RegistryEntry[];
muscleCategories: RegistryEntry[];
};
config: MappingConfig; // Full mapping configuration
}

This enables transforms to access other fields and configuration.


See Also