4
4
package replacement
5
5
6
6
import (
7
+ "encoding/json"
7
8
"fmt"
8
9
"strings"
9
10
@@ -188,6 +189,14 @@ func copyValueToTarget(target *yaml.RNode, value *yaml.RNode, selector *types.Ta
188
189
if selector .Options != nil && selector .Options .Create {
189
190
createKind = value .YNode ().Kind
190
191
}
192
+
193
+ // Check if this fieldPath contains structured data access
194
+ if err := setValueInStructuredData (target , value , fp , createKind ); err == nil {
195
+ // Successfully handled as structured data
196
+ continue
197
+ }
198
+
199
+ // Fall back to normal path handling
191
200
targetFieldList , err := target .Pipe (& yaml.PathMatcher {
192
201
Path : kyaml_utils .SmarterPathSplitter (fp , "." ),
193
202
Create : createKind })
@@ -204,7 +213,7 @@ func copyValueToTarget(target *yaml.RNode, value *yaml.RNode, selector *types.Ta
204
213
205
214
for _ , t := range targetFields {
206
215
if err := setFieldValue (selector .Options , t , value ); err != nil {
207
- return err
216
+ return fmt . Errorf ( "%w" , err )
208
217
}
209
218
}
210
219
}
@@ -247,3 +256,146 @@ func setFieldValue(options *types.FieldOptions, targetField *yaml.RNode, value *
247
256
248
257
return nil
249
258
}
259
+
260
+ // setValueInStructuredData handles setting values within structured data (JSON/YAML) in scalar fields
261
+ func setValueInStructuredData (target * yaml.RNode , value * yaml.RNode , fieldPath string , createKind yaml.Kind ) error {
262
+ pathParts := kyaml_utils .SmarterPathSplitter (fieldPath , "." )
263
+ if len (pathParts ) < 2 {
264
+ return fmt .Errorf ("not a structured data path" )
265
+ }
266
+
267
+ // Find the potential scalar field that might contain structured data
268
+ var scalarFieldPath []string
269
+ var structuredDataPath []string
270
+ var foundScalar = false
271
+
272
+ // Try to find where the scalar field ends and structured data begins
273
+ for i := 1 ; i <= len (pathParts ); i ++ {
274
+ potentialScalarPath := pathParts [:i ]
275
+ scalarField , err := target .Pipe (yaml .Lookup (potentialScalarPath ... ))
276
+ if err != nil {
277
+ continue
278
+ }
279
+ if scalarField != nil && scalarField .YNode ().Kind == yaml .ScalarNode && i < len (pathParts ) {
280
+ // Try to parse the scalar value as structured data
281
+ scalarValue := scalarField .YNode ().Value
282
+ var parsedNode yaml.Node
283
+ if err := yaml .Unmarshal ([]byte (scalarValue ), & parsedNode ); err == nil {
284
+ // Successfully parsed - this is structured data
285
+ scalarFieldPath = potentialScalarPath
286
+ structuredDataPath = pathParts [i :]
287
+ foundScalar = true
288
+ break
289
+ }
290
+ }
291
+ }
292
+
293
+ if ! foundScalar {
294
+ return fmt .Errorf ("no structured data found in path" )
295
+ }
296
+
297
+ // Get the scalar field containing structured data
298
+ scalarField , err := target .Pipe (yaml .Lookup (scalarFieldPath ... ))
299
+ if err != nil {
300
+ return fmt .Errorf ("%w" , err )
301
+ }
302
+
303
+ // Parse the structured data
304
+ scalarValue := scalarField .YNode ().Value
305
+ var parsedNode yaml.Node
306
+ if err := yaml .Unmarshal ([]byte (scalarValue ), & parsedNode ); err != nil {
307
+ return fmt .Errorf ("%w" , err )
308
+ }
309
+
310
+ structuredData := yaml .NewRNode (& parsedNode )
311
+
312
+ // Navigate to the target location within the structured data
313
+ targetInStructured , err := structuredData .Pipe (& yaml.PathMatcher {
314
+ Path : structuredDataPath ,
315
+ Create : createKind ,
316
+ })
317
+ if err != nil {
318
+ return fmt .Errorf ("%w" , err )
319
+ }
320
+
321
+ targetFields , err := targetInStructured .Elements ()
322
+ if err != nil {
323
+ return fmt .Errorf ("%w" , err )
324
+ }
325
+
326
+ if len (targetFields ) == 0 {
327
+ return fmt .Errorf ("unable to find field in structured data" )
328
+ }
329
+
330
+ // Set the value in the structured data
331
+ for _ , t := range targetFields {
332
+ if t .YNode ().Kind == yaml .ScalarNode {
333
+ t .YNode ().Value = value .YNode ().Value
334
+ } else {
335
+ t .SetYNode (value .YNode ())
336
+ }
337
+ }
338
+
339
+ // Serialize the modified structured data back to the scalar field
340
+ // Try to detect if original was JSON or YAML and preserve formatting
341
+ serializedData , err := serializeStructuredData (structuredData , scalarValue )
342
+ if err != nil {
343
+ return fmt .Errorf ("%w" , err )
344
+ }
345
+
346
+ // Update the original scalar field
347
+ scalarField .YNode ().Value = serializedData
348
+
349
+ return nil
350
+ }
351
+
352
+ // serializeStructuredData handles the serialization of structured data back to string format
353
+ // preserving the original format (JSON vs YAML) and style (pretty vs compact)
354
+ func serializeStructuredData (structuredData * yaml.RNode , originalValue string ) (string , error ) {
355
+ firstChar := rune (strings .TrimSpace (originalValue )[0 ])
356
+ if firstChar == '{' || firstChar == '[' {
357
+ return serializeAsJSON (structuredData , originalValue )
358
+ }
359
+
360
+ // Fallback to YAML format
361
+ return serializeAsYAML (structuredData )
362
+ }
363
+
364
+ // serializeAsJSON converts structured data back to JSON format
365
+ func serializeAsJSON (structuredData * yaml.RNode , originalValue string ) (string , error ) {
366
+ modifiedData , err := structuredData .String ()
367
+ if err != nil {
368
+ return "" , fmt .Errorf ("failed to serialize structured data: %w" , err )
369
+ }
370
+
371
+ // Parse the YAML output as JSON
372
+ var jsonData interface {}
373
+ if err := yaml .Unmarshal ([]byte (modifiedData ), & jsonData ); err != nil {
374
+ return "" , fmt .Errorf ("failed to unmarshal YAML data: %w" , err )
375
+ }
376
+
377
+ // Check if original was pretty-printed by looking for newlines and indentation
378
+ if strings .Contains (originalValue , "\n " ) && strings .Contains (originalValue , " " ) {
379
+ // Pretty-print the JSON to match original formatting
380
+ if prettyJSON , err := json .MarshalIndent (jsonData , "" , " " ); err == nil {
381
+ return string (prettyJSON ), nil
382
+ }
383
+ }
384
+
385
+ // Compact JSON
386
+ if compactJSON , err := json .Marshal (jsonData ); err == nil {
387
+ return string (compactJSON ), nil
388
+ }
389
+
390
+ return "" , fmt .Errorf ("failed to marshal JSON data" )
391
+ }
392
+
393
+ // serializeAsYAML converts structured data back to YAML format
394
+ func serializeAsYAML (structuredData * yaml.RNode ) (string , error ) {
395
+ modifiedData , err := structuredData .String ()
396
+ if err != nil {
397
+ return "" , fmt .Errorf ("failed to serialize YAML data: %w" , err )
398
+ }
399
+
400
+ return strings .TrimSpace (modifiedData ), nil
401
+ }
0 commit comments