@@ -2,9 +2,18 @@ import Mustache from "mustache";
22import { z } from "zod" ;
33import type { TransformerPlugin , ActionArgs } from "@curatedotfun/types" ;
44
5+ // Disable HTML escaping in Mustache
6+ Mustache . escape = function ( text ) {
7+ return text ;
8+ } ;
9+
510// Schema for the configuration
11+ const MappingValueSchema : z . ZodType < any > = z . lazy ( ( ) =>
12+ z . union ( [ z . string ( ) , z . array ( z . string ( ) ) , z . record ( MappingValueSchema ) ] ) ,
13+ ) ;
14+
615const ConfigSchema = z . object ( {
7- mappings : z . record ( z . union ( [ z . string ( ) , z . array ( z . string ( ) ) ] ) ) ,
16+ mappings : z . record ( MappingValueSchema ) ,
817} ) ;
918
1019type Config = z . infer < typeof ConfigSchema > ;
@@ -37,20 +46,22 @@ export default class ObjectTransformer
3746
3847 const output : Record < string , unknown > = { } ;
3948
40- for ( const [ outputField , template ] of Object . entries (
41- this . config . mappings ,
42- ) ) {
49+ // Recursive function to process mappings, including nested objects
50+ const processMapping = (
51+ template : string | string [ ] | Record < string , unknown > ,
52+ inputData : Record < string , unknown > ,
53+ ) : unknown => {
4354 // Helper function to process template value
4455 const processTemplate = ( template : string ) => {
45- const rendered = Mustache . render ( template , input ) ;
56+ const rendered = Mustache . render ( template , inputData ) ;
4657
4758 // If the template references a field that's an array or object, return it directly
4859 const fieldMatch = template . match ( / ^ \{ \{ ( [ ^ } ] + ) \} \} $ / ) ;
4960 if ( fieldMatch ) {
5061 const field = fieldMatch [ 1 ] ;
5162 const value = field
5263 . split ( "." )
53- . reduce ( ( obj : any , key ) => obj ?. [ key ] , input ) ;
64+ . reduce ( ( obj : any , key ) => obj ?. [ key ] , inputData ) ;
5465 if (
5566 Array . isArray ( value ) ||
5667 ( typeof value === "object" && value !== null )
@@ -71,10 +82,14 @@ export default class ObjectTransformer
7182 return rendered ;
7283 } ;
7384
74- // Process the template or array of templates
75- if ( Array . isArray ( template ) ) {
85+ // Process based on template type
86+ if ( typeof template === "string" ) {
87+ const result = processTemplate ( template ) ;
88+ // For string templates, preserve empty arrays but convert undefined to empty string
89+ return Array . isArray ( result ) ? result : ( result ?? "" ) ;
90+ } else if ( Array . isArray ( template ) ) {
7691 const results = template . map ( processTemplate ) ;
77- output [ outputField ] = results . reduce ( ( acc : unknown [ ] , result ) => {
92+ return results . reduce ( ( acc : unknown [ ] , result ) => {
7893 if ( result === undefined || result === "" ) {
7994 return acc ;
8095 }
@@ -85,11 +100,23 @@ export default class ObjectTransformer
85100 }
86101 return acc ;
87102 } , [ ] ) ;
88- } else {
89- const result = processTemplate ( template ) ;
90- // For non-array templates, preserve empty arrays but convert undefined to empty string
91- output [ outputField ] = Array . isArray ( result ) ? result : ( result ?? "" ) ;
103+ } else if ( typeof template === "object" && template !== null ) {
104+ // Handle nested object
105+ const nestedOutput : Record < string , unknown > = { } ;
106+ for ( const [ key , value ] of Object . entries ( template ) ) {
107+ nestedOutput [ key ] = processMapping ( value as any , inputData ) ;
108+ }
109+ return nestedOutput ;
92110 }
111+
112+ return template ;
113+ } ;
114+
115+ // Process each top-level mapping
116+ for ( const [ outputField , template ] of Object . entries (
117+ this . config . mappings ,
118+ ) ) {
119+ output [ outputField ] = processMapping ( template , input ) ;
93120 }
94121
95122 return output ;
0 commit comments