config-disassembler 0.9.2

Disassemble config files into smaller files and reassemble on demand.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# XML Support

The `xml` subcommand splits large XML files into smaller pieces and reassembles them back into the original XML.

```bash
config-disassembler xml disassemble <path> [options]
config-disassembler xml reassemble  <path> [extension] [--postpurge]
```

`<path>` may be a single XML file or a directory containing XML files.

---

## Basic usage

### Disassemble

```bash
config-disassembler xml disassemble flow.xml
```

Result:

```text
flow/
├── assignments/
├── decisions/
├── screens/
└── flow-meta.xml
```

### Reassemble

```bash
config-disassembler xml reassemble flow
```

---

## Disassemble options

| Option | Description | Default |
|---|---|---|
| `--unique-id-elements <list>` | Comma-separated fields used to derive filenames | none |
| `--strategy <name>` | `unique-id` or `grouped-by-tag` | `unique-id` |
| `--format <fmt>` | Output format: `xml`, `json`, `json5`, `yaml` | `xml` |
| `--prepurge` | Remove existing output before writing | `false` |
| `--postpurge` | Delete source after success | `false` |
| `--ignore-path <path>` | Ignore file path | `.cdignore` |
| `-p`, `--split-tags <spec>` | Split/group nested tags into subdirectories | none |
| `--multi-level <spec>` | Further disassemble matching files | none |

---

## Reassemble options

| Option | Description | Default |
|---|---|---|
| `<extension>` | Extension for rebuilt XML | `xml` |
| `--postpurge` | Delete disassembled directory after success | `false` |

---

## Disassembly strategies

### unique-id (default)

Each nested XML element is written to its own file using a unique identifier.

```bash
config-disassembler xml disassemble flow.xml \
  --unique-id-elements name,id
```

Best for fine-grained diffs, version control, and large metadata files.

Example:

```text
flow/
├── decisions/
│   ├── CheckAccount.flow-meta.xml
│   └── ValidateUser.flow-meta.xml
├── screens/
└── flow-meta.xml
```

If no unique identifier is found, filenames fall back to an 8-character SHA-256 hash:

```text
419e0199.flow-meta.xml
```

#### Compound unique IDs

Combine multiple fields with `+`:

```bash
config-disassembler xml disassemble profile.xml \
  --unique-id-elements \
  "actionName+pageOrSobjectType+formFactor+profile"
```

Resolved values are joined with `__`:

```text
View__Account__Large__Admin.profileActionOverrides-meta.xml
```

Useful when no single field uniquely identifies sibling elements.

---

### grouped-by-tag

Groups nested elements with the same tag into shared files.

```bash
config-disassembler xml disassemble flow.xml \
  --strategy grouped-by-tag
```

Best for fewer files, simpler layouts, and quick inspection.

Example:

```text
flow/
├── assignments.flow-meta.xml
├── decisions.flow-meta.xml
├── screens.flow-meta.xml
└── flow-meta.xml
```

Reassembly preserves the original structure and ordering.

---

## Split tags

With `grouped-by-tag`, specific nested tags can be split or grouped into subdirectories.

Rule format:

```text
tag:mode:field
```

Or with a path:

```text
tag:path:mode:field
```

- `mode=split` → one file per item
- `mode=group` → one file per grouped field value

Example:

```bash
config-disassembler xml disassemble permissionset.xml \
  --strategy grouped-by-tag \
  -p "objectPermissions:split:object,fieldPermissions:group:field"
```

Result:

```text
permissionset/
├── objectPermissions/
│   ├── Account.objectPermissions-meta.xml
│   └── Contact.objectPermissions-meta.xml
├── fieldPermissions/
└── permissionset-meta.xml
```

Reassembly automatically merges split directories back into the original XML.

---

## Output formats

XML can be split into:

- XML
- JSON
- JSON5
- YAML

```bash
config-disassembler xml disassemble flow.xml --format yaml
config-disassembler xml disassemble flow.xml --format json5
```

Regardless of split format, reassembly always produces XML.

---

## XML parser behavior

Parsing uses `quick-xml`. Supported features:

- CDATA preservation
- comment preservation
- attribute preservation

Attributes use `@` prefixes:

```xml
<root version="1.0">
```

Becomes:

```json
{ "@version": "1.0" }
```

CDATA is represented using `#cdata`.

---

## Filename safety

Resolved filenames are automatically sanitized for cross-platform compatibility:

- Path separators and reserved characters are replaced with `_`
- Invalid trailing characters are removed
- Sibling filename collisions are detected; SHA-based fallback is used when they occur

Guarantees deterministic, collision-free output across Windows, macOS, and Linux.

Example:

```text
TrustFile Transaction Sync/Import Complete
```

Becomes:

```text
TrustFile Transaction Sync_Import Complete.flow-meta.xml
```

---

## Ignore files

Directory disassembly supports `.gitignore`-style filtering via `.cdignore`:

```text
**/generated/
**/secret.xml
```

```bash
config-disassembler xml disassemble metadata/
```

For backward compatibility, `.xmldisassemblerignore` is also recognized when `.cdignore` is absent.

---

## Logging

```bash
RUST_LOG=debug config-disassembler xml disassemble flow.xml
```

---

## Multi-level disassembly

Multi-level disassembly further splits specific output files after the initial disassembly pass. Useful for deeply nested metadata structures.

Rule format:

```text
file_pattern:root_to_strip:unique_id_elements
```

Example:

```bash
config-disassembler xml disassemble \
  Cloud_Kicks_Inner_Circle.loyaltyProgramSetup-meta.xml \
  --unique-id-elements "fullName,name,processName" \
  --multi-level \
  "programProcesses:programProcesses:parameterName,ruleName"
```

This:

1. Disassembles the top-level XML
2. Matches files containing `programProcesses`
3. Unwraps the `programProcesses` root
4. Disassembles nested items again using `parameterName` and `ruleName`

A `.multi_level.json` file is written automatically so reassembly can reconstruct the original hierarchy. No additional flags are required during reassembly.

### Multiple rules

Separate rules with `;`:

```bash
config-disassembler xml disassemble Sample.multi-meta.xml \
  --unique-id-elements "id,name,label" \
  --multi-level \
  "sectionA:sectionA:id;sectionB:sectionB:name"
```

Whitespace is trimmed. Empty trailing rules are ignored.

### Reassembly caveat

Multi-level reassembly removes intermediate directories during reconstruction, even without `--postpurge`. This is necessary so higher-level reassembly can merge rebuilt XML files correctly.

Use version control if you need to preserve intermediate disassembly trees.

---

## Sidecar elements

`--sidecar-elements` extracts the text content of named XML elements into companion files during disassembly and reinjects them during reassembly. Useful for metadata types that embed large non-XML blobs (OpenAPI schemas, WSDL, etc.) inside an XML element.

### Format

```text
element:extension[,element:extension,...]
```

Each pair names the XML element to extract and the file extension for the companion file. Multiple pairs are separated by commas.

### Disassemble

```bash
config-disassembler xml disassemble \
  BankService.externalServiceRegistration-meta.xml \
  --sidecar-elements schema:yaml
```

Result:

```text
BankService/
├── BankService.yaml       ← extracted <schema> content
├── .sidecars.json         ← auto-detect metadata for reassembly
├── .key_order.json
└── (disassembled shards)
```

- The element is removed from the disassembled XML shards.
- The companion file is named `{directory}.{extension}` and written inside the disassembled directory.
- `.sidecars.json` is written automatically so reassembly can locate and reinject sidecar files without any additional flags.

### Format conversion

The extracted text is converted to match the declared extension:

| Extension | YAML source | JSON source |
|---|---|---|
| `yaml` / `yml` | passes through unchanged | converted to YAML |
| `json` | converted to pretty JSON | prettified |
| anything else | passes through unchanged | passes through unchanged |

This mirrors the Salesforce `decomposeExternalServiceRegistrationBeta` preset: JSON schemas are always stored as YAML when `extension` is `yaml`.

### Reassemble

```bash
config-disassembler xml reassemble BankService
```

Reassembly auto-detects sidecars from `.sidecars.json` written during disassembly — no flag required. The sidecar file content is injected back verbatim into the XML element.

### Multiple sidecars

```bash
config-disassembler xml disassemble service.xml \
  --sidecar-elements "schema:yaml,wsdl:xml"
```

Each spec produces its own companion file.

---

---

## Round-trip verification (library API)

`verify_roundtrip` disassembles and reassembles an XML file inside an isolated temp directory, then reports whether the reconstructed file matches the original. It never touches the caller's file. This is a library-only API — no CLI subcommand yet.

```rust
use config_disassembler::xml::{verify_roundtrip, RoundtripStatus, VerifyOptions};

let status = verify_roundtrip("flow.xml", VerifyOptions::default()).await?;
match status {
    RoundtripStatus::Identical => println!("byte-identical round trip"),
    RoundtripStatus::Reordered => println!("semantically equal; only sibling/attribute order changed"),
    RoundtripStatus::Drift(reason) => println!("genuine content loss: {reason}"),
}
```

`VerifyOptions` mirrors the disassemble options that affect structure (`unique_id_elements`, `strategy`, `ignore_path`, `multi_level_rules`, `decompose_rules`, `sidecar_specs`) — set the same values you'd pass to disassembly so the round trip exercises the same rules.

Comparison ignores sibling/attribute order (`Reordered`) since element order is not guaranteed to survive a disassemble/reassemble cycle, but reports `Drift` when content is genuinely lost or changed. Useful for CI dry-run checks: verify a metadata file round-trips cleanly without writing anything to the working tree.

---

## Examples

See [examples.md](examples.md) for complete before/after layouts and real-world metadata examples.