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,127 @@ 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
+ // if strings.TrimSpace(scalarValue)[0] == '{' || strings.TrimSpace(scalarValue)[0] == '[' {
342
+ firstChar := strings .TrimSpace (scalarValue )[0 ]
343
+ if firstChar == '{' || firstChar == '[' {
344
+ // Original was JSON - convert back to JSON
345
+ var jsonData interface {}
346
+ modifiedData , err := structuredData .String ()
347
+ if err != nil {
348
+ return fmt .Errorf ("%w" , err )
349
+ }
350
+
351
+ // Parse the YAML output as JSON
352
+ if err := yaml .Unmarshal ([]byte (modifiedData ), & jsonData ); err != nil {
353
+ return fmt .Errorf ("%w" , err )
354
+ }
355
+
356
+ // Check if original was pretty-printed by looking for newlines and indentation
357
+ if strings .Contains (scalarValue , "\n " ) && strings .Contains (scalarValue , " " ) {
358
+ // Pretty-print the JSON to match original formatting
359
+ if prettyJSON , err := json .MarshalIndent (jsonData , "" , " " ); err == nil {
360
+ scalarField .YNode ().Value = string (prettyJSON )
361
+ return nil
362
+ }
363
+ } else {
364
+ // Compact JSON
365
+ if compactJSON , err := json .Marshal (jsonData ); err == nil {
366
+ scalarField .YNode ().Value = string (compactJSON )
367
+ return nil
368
+ }
369
+ }
370
+ }
371
+
372
+ // Fallback to YAML format
373
+ modifiedData , err := structuredData .String ()
374
+ if err != nil {
375
+ return fmt .Errorf ("%w" , err )
376
+ }
377
+
378
+ // Update the original scalar field
379
+ scalarField .YNode ().Value = strings .TrimSpace (modifiedData )
380
+
381
+ return nil
382
+ }
0 commit comments