sf-decomposer 6.10.0 → 6.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +145 -18
  3. package/lib/commands/decomposer/decompose.d.ts +3 -1
  4. package/lib/commands/decomposer/decompose.js +20 -1
  5. package/lib/commands/decomposer/decompose.js.map +1 -1
  6. package/lib/commands/decomposer/recompose.d.ts +2 -1
  7. package/lib/commands/decomposer/recompose.js +11 -1
  8. package/lib/commands/decomposer/recompose.js.map +1 -1
  9. package/lib/core/decomposeMetadataTypes.js +49 -8
  10. package/lib/core/decomposeMetadataTypes.js.map +1 -1
  11. package/lib/core/recomposeMetadataTypes.js +43 -5
  12. package/lib/core/recomposeMetadataTypes.js.map +1 -1
  13. package/lib/helpers/configOverrides.d.ts +33 -0
  14. package/lib/helpers/configOverrides.js +132 -0
  15. package/lib/helpers/configOverrides.js.map +1 -0
  16. package/lib/helpers/types.d.ts +15 -2
  17. package/lib/hooks/prerun.js +34 -26
  18. package/lib/hooks/prerun.js.map +1 -1
  19. package/lib/hooks/scopedPostRetrieve.js +39 -40
  20. package/lib/hooks/scopedPostRetrieve.js.map +1 -1
  21. package/lib/metadata/parseManifest.d.ts +5 -0
  22. package/lib/metadata/parseManifest.js +164 -0
  23. package/lib/metadata/parseManifest.js.map +1 -0
  24. package/lib/service/core/moveFiles.js +20 -8
  25. package/lib/service/core/moveFiles.js.map +1 -1
  26. package/lib/service/decompose/decomposeFileHandler.d.ts +1 -1
  27. package/lib/service/decompose/decomposeFileHandler.js +41 -2
  28. package/lib/service/decompose/decomposeFileHandler.js.map +1 -1
  29. package/lib/service/recompose/recomposeFileHandler.d.ts +1 -1
  30. package/lib/service/recompose/recomposeFileHandler.js +57 -2
  31. package/lib/service/recompose/recomposeFileHandler.js.map +1 -1
  32. package/messages/decomposer.decompose.md +15 -1
  33. package/messages/decomposer.recompose.md +11 -1
  34. package/oclif.manifest.json +37 -7
  35. package/package.json +1 -4
package/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@
5
5
 
6
6
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
7
7
 
8
+ ## [6.12.0](https://github.com/mcarvin8/sf-decomposer/compare/v6.11.0...v6.12.0) (2026-04-27)
9
+
10
+
11
+ ### Features
12
+
13
+ * add per-metadata-type overrides for decompose ([#407](https://github.com/mcarvin8/sf-decomposer/issues/407)) ([43be31d](https://github.com/mcarvin8/sf-decomposer/commit/43be31d6190e095a0dbc5b763e2439582c5b4214))
14
+
15
+ ## [6.11.0](https://github.com/mcarvin8/sf-decomposer/compare/v6.10.0...v6.11.0) (2026-04-24)
16
+
17
+
18
+ ### Features
19
+
20
+ * add --manifest/-x flag for scoped decompose and recompose ([#405](https://github.com/mcarvin8/sf-decomposer/issues/405)) ([2a1f39f](https://github.com/mcarvin8/sf-decomposer/commit/2a1f39f572362899265c6d6092adb8284b9c4427))
21
+
8
22
  ## [6.10.0](https://github.com/mcarvin8/sf-decomposer/compare/v6.9.0...v6.10.0) (2026-04-23)
9
23
 
10
24
 
package/README.md CHANGED
@@ -17,6 +17,7 @@ A Salesforce CLI plugin that **decomposes** large metadata XML files into smalle
17
17
  - [Commands](#commands)
18
18
  - [sf decomposer decompose](#sf-decomposer-decompose)
19
19
  - [sf decomposer recompose](#sf-decomposer-recompose)
20
+ - [Manifest-scoped runs](#manifest-scoped-runs)
20
21
  - [Decompose Strategies](#decompose-strategies)
21
22
  - [Custom Labels](#custom-labels-decomposition)
22
23
  - [Permission Sets (grouped-by-tag)](#additional-permission-set-decomposition)
@@ -25,6 +26,7 @@ A Salesforce CLI plugin that **decomposes** large metadata XML files into smalle
25
26
  - [Exceptions](#exceptions)
26
27
  - [Troubleshooting](#troubleshooting)
27
28
  - [Hooks](#hooks)
29
+ - [Per-Type Overrides](#per-type-overrides)
28
30
  - [Ignore Files](#ignore-files)
29
31
  - [.forceignore](#forceignore)
30
32
  - [.sfdecomposerignore](#sfdecomposerignore)
@@ -66,11 +68,18 @@ A Salesforce CLI plugin that **decomposes** large metadata XML files into smalle
66
68
  sf project deploy start
67
69
  ```
68
70
 
71
+ Or scope the recompose to just the components in your deploy manifest:
72
+
73
+ ```bash
74
+ sf decomposer recompose -x "manifest/package.xml"
75
+ sf project deploy start -x "manifest/package.xml"
76
+ ```
77
+
69
78
  ---
70
79
 
71
80
  ## Requirements
72
81
 
73
- The [xml-disassembler](https://github.com/mcarvin8/xml-disassembler) NodeJS dependency, which depends on a Rust crate, ships with native binaries for these platforms:
82
+ The [xml-disassembler-node](https://github.com/mcarvin8/xml-disassembler-node) package, which depends on a Rust crate, ships with native binaries for these platforms:
74
83
 
75
84
  | Platform | Architectures |
76
85
  | ----------- | ---------------------------------- |
@@ -78,7 +87,7 @@ The [xml-disassembler](https://github.com/mcarvin8/xml-disassembler) NodeJS depe
78
87
  | **Linux** | x64, arm64, ia32 |
79
88
  | **Windows** | x64 |
80
89
 
81
- If other platforms or architectures require support, please open an issue in the [Rust repository](https://github.com/mcarvin8/xml-disassembler-rust).
90
+ If other platforms or architectures require support, please open an issue in [xml-disassembler-node](https://github.com/mcarvin8/xml-disassembler-node/issues).
82
91
 
83
92
  ---
84
93
 
@@ -90,6 +99,7 @@ Salesforce’s built-in decomposition is limited. sf-decomposer gives admins and
90
99
 
91
100
  - **Broader metadata support** – Works with most Metadata API types, not just the subset Salesforce decomposes.
92
101
  - **Selective decomposition** – Decompose only what you need; use [.sfdecomposerignore](#sfdecomposerignore) to skip specific files.
102
+ - **Manifest-scoped runs** – Pass `-x package.xml` to decompose or recompose only the components listed in a Salesforce manifest, mirroring `sf project deploy start -x`. Ideal for CI/CD pipelines that only ship a subset of metadata per deployment.
93
103
  - **Two [strategies](#decompose-strategies)**:
94
104
  - **unique-id** (default): one file per nested element, named by content or hash.
95
105
  - **grouped-by-tag**: one file per tag (e.g. all `fieldPermissions` in a permission set in `fieldPermissions.xml`). Use `--decompose-nested-permissions` for deeper permission set and muting permission set decomposition.
@@ -114,21 +124,25 @@ Decomposes metadata in all local package directories (from `sfdx-project.json`)
114
124
 
115
125
  ```
116
126
  USAGE
117
- $ sf decomposer decompose -m <value> -f <value> -i <value> -s <value> [--prepurge --postpurge -p --json]
127
+ $ sf decomposer decompose [-m <value>] [-x <value>] [-f <value>] [-i <value>] [-s <value>] [--prepurge --postpurge -p -c --json]
118
128
 
119
129
  FLAGS
120
- -m, --metadata-type=<value> Metadata suffix to process (e.g. flow, labels). Repeatable.
130
+ -m, --metadata-type=<value> Metadata suffix to process (e.g. flow, labels). Repeatable. Optional when --manifest is provided.
131
+ -x, --manifest=<value> Path to a package.xml manifest. When provided, only the components listed in the manifest are decomposed.
121
132
  -f, --format=<value> Output format: xml | yaml | json | json5 [default: xml]
122
133
  -i, --ignore-package-directory=<value> Package directory to skip (as in sfdx-project.json). Repeatable.
123
134
  -s, --strategy=<value> unique-id | grouped-by-tag [default: unique-id]
124
135
  --prepurge Remove existing decomposed files before decomposing [default: false]
125
136
  --postpurge Remove original metadata files after decomposing [default: false]
126
137
  -p, --decompose-nested-permissions With grouped-by-tag, further decompose permission set and muting permission set object/field permissions
138
+ -c, --config Load per-metadata-type overrides from .sfdecomposer.config.json in the repo root. Only the "overrides" array is consumed. See Per-Type Overrides. [default: false]
127
139
 
128
140
  GLOBAL FLAGS
129
141
  --json Output as JSON.
130
142
  ```
131
143
 
144
+ > At least one of `--metadata-type` or `--manifest` is required. When both are supplied, the run is scoped to the intersection of the two.
145
+
132
146
  **Examples**
133
147
 
134
148
  ```bash
@@ -140,6 +154,12 @@ sf decomposer decompose -m "flow" -m "labels" -f "yaml" --prepurge --postpurge
140
154
 
141
155
  # Decompose flows, excluding the force-app package
142
156
  sf decomposer decompose -m "flow" -i "force-app"
157
+
158
+ # Decompose only the components listed in a manifest
159
+ sf decomposer decompose -x "manifest/package.xml" --prepurge
160
+
161
+ # Restrict a manifest run to a single metadata type
162
+ sf decomposer decompose -x "manifest/package.xml" -m "permissionset"
143
163
  ```
144
164
 
145
165
  ### sf decomposer recompose
@@ -148,10 +168,11 @@ Recomposes decomposed files into deployment-compatible metadata.
148
168
 
149
169
  ```
150
170
  USAGE
151
- $ sf decomposer recompose -m <value> -i <value> [--postpurge --json]
171
+ $ sf decomposer recompose [-m <value>] [-x <value>] [-i <value>] [--postpurge --json]
152
172
 
153
173
  FLAGS
154
- -m, --metadata-type=<value> Metadata suffix to process (e.g. flow, labels). Repeatable.
174
+ -m, --metadata-type=<value> Metadata suffix to process (e.g. flow, labels). Repeatable. Optional when --manifest is provided.
175
+ -x, --manifest=<value> Path to a package.xml manifest. When provided, only the components listed in the manifest are recomposed.
155
176
  -i, --ignore-package-directory=<value> Package directory to skip. Repeatable.
156
177
  --postpurge Remove decomposed files after recomposing [default: false]
157
178
 
@@ -159,11 +180,52 @@ GLOBAL FLAGS
159
180
  --json Output as JSON.
160
181
  ```
161
182
 
183
+ > At least one of `--metadata-type` or `--manifest` is required. When both are supplied, the run is scoped to the intersection of the two.
184
+
162
185
  **Examples**
163
186
 
164
187
  ```bash
165
188
  sf decomposer recompose -m "flow" --postpurge
166
189
  sf decomposer recompose -m "flow" -i "force-app"
190
+
191
+ # Recompose only the components listed in a deploy manifest before deploying
192
+ sf decomposer recompose -x "manifest/package.xml"
193
+ sf project deploy start -x "manifest/package.xml"
194
+ ```
195
+
196
+ ### Manifest-scoped runs
197
+
198
+ The `-x` / `--manifest` flag accepts any standard Salesforce `package.xml` and limits the work to just the components it lists. This is especially useful for CI/CD pipelines that deploy a subset of metadata per change.
199
+
200
+ How it works:
201
+
202
+ - The manifest is parsed with `@salesforce/source-deploy-retrieve`'s `ManifestResolver`, so the same XML you pass to `sf project deploy start -x` is honored here.
203
+ - For each entry, the plugin resolves the matching parent metadata files in your local package directories (using each metadata type's `directoryName`, `suffix`, `strictDirectoryName`, and `folderType` from the SDR registry).
204
+ - Only those files are decomposed/recomposed; everything else on disk is left untouched.
205
+ - Wildcards (`<members>*</members>`) expand against your local source. Folder-typed members (e.g. `MyFolder/MyReport`) are resolved by walking the folder.
206
+ - Types in the manifest that the plugin does not support (e.g. `CustomObject`, `ApexClass`) are skipped with a warning instead of failing the run, so a single manifest can drive both deploys and decomposer runs.
207
+ - If both `--metadata-type` and `--manifest` are provided, the run is scoped to the intersection (only types present in both).
208
+
209
+ Example manifest:
210
+
211
+ ```xml
212
+ <?xml version="1.0" encoding="UTF-8"?>
213
+ <Package xmlns="http://soap.sforce.com/2006/04/metadata">
214
+ <types>
215
+ <members>HR_Admin</members>
216
+ <name>PermissionSet</name>
217
+ </types>
218
+ <types>
219
+ <members>Case</members>
220
+ <name>Workflow</name>
221
+ </types>
222
+ <version>58.0</version>
223
+ </Package>
224
+ ```
225
+
226
+ ```bash
227
+ sf decomposer recompose -x "manifest/package.xml"
228
+ sf project deploy start -x "manifest/package.xml"
167
229
  ```
168
230
 
169
231
  ---
@@ -297,17 +359,83 @@ Put **.sfdecomposer.config.json** in the project root to run:
297
359
  - **After** `sf project retrieve start`: decompose.
298
360
  - **Before** `sf project deploy start` / `sf project deploy validate`: recompose.
299
361
 
300
- Copy and customize the [sample config](https://raw.githubusercontent.com/mcarvin8/sf-decomposer/main/examples/.sfdecomposer.config.json).
362
+ Copy and customize the [sample config](https://raw.githubusercontent.com/mcarvin8/sf-decomposer/main/examples/.sfdecomposer.config.json), or the [sample config with per-type overrides](https://raw.githubusercontent.com/mcarvin8/sf-decomposer/main/examples/.sfdecomposer.config.overrides.json) to vary format/strategy/etc. by metadata type.
363
+
364
+ | Option | Required | Description |
365
+ | ---------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
366
+ | `metadataSuffixes` | Conditional | Comma-separated metadata suffixes to decompose/recompose. Required unless `manifest` is set; when both are set, the run is scoped to the intersection. |
367
+ | `manifest` | Conditional | Path (relative to the project root) to a `package.xml` manifest. When set, only the components listed in the manifest are decomposed/recomposed. See `-x` above. |
368
+ | `ignorePackageDirectories` | No | Comma-separated package directories to skip. |
369
+ | `prePurge` | No | Remove existing decomposed files before decomposing (default: false). |
370
+ | `postPurge` | No | After decompose: remove originals; after recompose: remove decomposed files (default: false). |
371
+ | `decomposedFormat` | No | xml, json, json5, or yaml (default: xml). |
372
+ | `strategy` | No | `unique-id` \| `grouped-by-tag` (default: unique-id). |
373
+ | `decomposeNestedPermissions` | No | With grouped-by-tag, set true to further decompose permission set and muting permission set object/field permissions. |
374
+ | `overrides` | No | Array of per-metadata-type overrides for `decomposedFormat`, `strategy`, `decomposeNestedPermissions`, `prePurge`, and `postPurge`. See [Per-Type Overrides](#per-type-overrides). |
375
+
376
+ ---
377
+
378
+ ## Per-Type Overrides
379
+
380
+ Per-type overrides apply to **decompose only**. Recompose is a deterministic round-trip — it auto-detects format from the on-disk files and does not depend on strategy — so it ignores the `overrides` array.
381
+
382
+ By default, a single decompose run uses one format and one strategy across every metadata type. The optional `overrides` array in `.sfdecomposer.config.json` lets you vary a small set of options per metadata suffix without splitting the run into multiple invocations.
383
+
384
+ ```json
385
+ {
386
+ "metadataSuffixes": "labels,workflow,profile,flow,permissionset",
387
+ "ignorePackageDirectories": "force-app,examples",
388
+ "prePurge": true,
389
+ "postPurge": true,
390
+ "decomposedFormat": "xml",
391
+ "strategy": "unique-id",
392
+ "overrides": [
393
+ { "metadataTypes": ["flow"], "decomposedFormat": "yaml" },
394
+ {
395
+ "metadataTypes": ["permissionset", "mutingpermissionset"],
396
+ "strategy": "grouped-by-tag",
397
+ "decomposeNestedPermissions": true
398
+ }
399
+ ]
400
+ }
401
+ ```
402
+
403
+ ### What can be overridden
404
+
405
+ | Field | Notes |
406
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
407
+ | `metadataTypes` | Required. Array of metadata suffixes (same vocabulary as `--metadata-type` / `metadataSuffixes`). Each suffix may appear in at most one override. |
408
+ | `decomposedFormat` | `xml` \| `json` \| `json5` \| `yaml`. |
409
+ | `strategy` | `unique-id` \| `grouped-by-tag`. Hard rules still win — `labels` and `loyaltyProgramSetup` are always treated as `unique-id`. |
410
+ | `decomposeNestedPermissions` | Only applies to `permissionset` / `mutingpermissionset` with `grouped-by-tag`. |
411
+ | `prePurge` | Per-type prePurge (decompose). |
412
+ | `postPurge` | Per-type postPurge (decompose: remove originals after decomposing). |
413
+
414
+ Run-scope options (`metadataSuffixes`, `manifest`, `ignorePackageDirectories`) are **not** valid inside an override; the plugin will throw if they are present.
415
+
416
+ ### Precedence
417
+
418
+ For each metadata type, the effective value is resolved as:
419
+
420
+ 1. The per-type override value, if set.
421
+ 2. Otherwise, the run-wide value (CLI flag, hook config top-level field, or built-in default).
422
+ 3. Hard plugin rules (e.g. labels → `unique-id`) still override both.
423
+
424
+ ### Opting in from the CLI
425
+
426
+ CLI users can opt into overrides on `decompose` with the boolean `--config` (`-c`) flag. When set, the plugin reads `.sfdecomposer.config.json` from the repo root (the nearest ancestor directory that contains `sfdx-project.json`):
427
+
428
+ ```bash
429
+ sf decomposer decompose -m "flow" -m "permissionset" -c
430
+ ```
431
+
432
+ When `--config` is set, **only** the `overrides` array is consumed from the file. Top-level fields like `decomposedFormat`, `strategy`, `metadataSuffixes`, etc. are ignored — the CLI flags remain the source of truth for run-wide values. This keeps direct CLI behavior predictable and lets you reuse the same config file as the post-retrieve hook without any surprises.
433
+
434
+ If `--config` is set but `.sfdecomposer.config.json` is missing from the repo root, the command fails with a clear error.
435
+
436
+ `recompose` does not accept `--config` because it does not need the override information — format is auto-detected from the decomposed files on disk and recompose does not depend on strategy.
301
437
 
302
- | Option | Required | Description |
303
- | ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
304
- | `metadataSuffixes` | Yes | Comma-separated metadata suffixes to decompose/recompose. |
305
- | `ignorePackageDirectories` | No | Comma-separated package directories to skip. |
306
- | `prePurge` | No | Remove existing decomposed files before decomposing (default: false). |
307
- | `postPurge` | No | After decompose: remove originals; after recompose: remove decomposed files (default: false). |
308
- | `decomposedFormat` | No | xml, json, json5, or yaml (default: xml). |
309
- | `strategy` | No | `unique-id` \| `grouped-by-tag` (default: unique-id). |
310
- | `decomposeNestedPermissions` | No | With grouped-by-tag, set true to further decompose permission set and muting permission set object/field permissions. |
438
+ The post-retrieve hook automatically picks up `overrides` from `.sfdecomposer.config.json` — no extra setup required. Existing config files without an `overrides` field continue to behave exactly as before.
311
439
 
312
440
  ---
313
441
 
@@ -336,7 +464,6 @@ Bugs and feature requests: [open an issue](https://github.com/mcarvin8/sf-decomp
336
464
  ## Built With
337
465
 
338
466
  - [xml-disassembler](https://github.com/mcarvin8/xml-disassembler) – Disassemble XML into smaller, manageable files and reassemble when needed. Node.js + Rust (Neon). Includes prebuilt binaries for macOS (x64, arm64), Linux (x64, arm64, ia32), and Windows (x64).
339
- - [fs-extra](https://github.com/jprichardson/node-fs-extra) – Node.js: extra methods for the `fs` object like copy(), remove(), mkdirs().
340
467
  - [@salesforce/source-deploy-retrieve](https://github.com/forcedotcom/source-deploy-retrieve) – JavaScript toolkit for working with Salesforce metadata.
341
468
 
342
469
  ---
@@ -347,4 +474,4 @@ Contributions are welcome. See [CONTRIBUTING.md](https://github.com/mcarvin8/sf-
347
474
 
348
475
  ## License
349
476
 
350
- MIT. See [LICENSE](https://raw.githubusercontent.com/mcarvin8/sf-decomposer/main/LICENSE.md).
477
+ [MIT](https://raw.githubusercontent.com/mcarvin8/sf-decomposer/main/LICENSE.md)
@@ -5,13 +5,15 @@ export default class DecomposerDecompose extends SfCommand<DecomposerResult> {
5
5
  static readonly description: string;
6
6
  static readonly examples: string[];
7
7
  static readonly flags: {
8
- 'metadata-type': import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
8
+ 'metadata-type': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ manifest: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
10
  prepurge: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
11
  postpurge: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
12
  format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
12
13
  'ignore-package-directory': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
14
  strategy: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
14
15
  'decompose-nested-permissions': import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
+ config: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
17
  };
16
18
  run(): Promise<DecomposerResult>;
17
19
  }
@@ -3,6 +3,7 @@ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
3
3
  import { Messages } from '@salesforce/core';
4
4
  import { DECOMPOSED_FILE_TYPES, DECOMPOSED_STRATEGIES } from '../../helpers/constants.js';
5
5
  import { decomposeMetadataTypes } from '../../core/decomposeMetadataTypes.js';
6
+ import { loadOverridesFromConfig, resolveDefaultConfigPath } from '../../helpers/configOverrides.js';
6
7
  Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
8
  const messages = Messages.loadMessages('sf-decomposer', 'decomposer.decompose');
8
9
  export default class DecomposerDecompose extends SfCommand {
@@ -14,7 +15,13 @@ export default class DecomposerDecompose extends SfCommand {
14
15
  summary: messages.getMessage('flags.metadata-type.summary'),
15
16
  char: 'm',
16
17
  multiple: true,
17
- required: true,
18
+ required: false,
19
+ }),
20
+ manifest: Flags.file({
21
+ summary: messages.getMessage('flags.manifest.summary'),
22
+ char: 'x',
23
+ required: false,
24
+ exists: true,
18
25
  }),
19
26
  prepurge: Flags.boolean({
20
27
  summary: messages.getMessage('flags.prepurge.summary'),
@@ -54,9 +61,19 @@ export default class DecomposerDecompose extends SfCommand {
54
61
  required: false,
55
62
  default: false,
56
63
  }),
64
+ config: Flags.boolean({
65
+ summary: messages.getMessage('flags.config.summary'),
66
+ char: 'c',
67
+ required: false,
68
+ default: false,
69
+ }),
57
70
  };
58
71
  async run() {
59
72
  const { flags } = await this.parse(DecomposerDecompose);
73
+ if (!flags['metadata-type'] && !flags['manifest']) {
74
+ throw messages.createError('error.missingMetadataOrManifest');
75
+ }
76
+ const overrides = flags['config'] ? await loadOverridesFromConfig(await resolveDefaultConfigPath()) : undefined;
60
77
  return decomposeMetadataTypes({
61
78
  metadataTypes: flags['metadata-type'],
62
79
  prepurge: flags['prepurge'],
@@ -65,6 +82,8 @@ export default class DecomposerDecompose extends SfCommand {
65
82
  ignoreDirs: flags['ignore-package-directory'],
66
83
  strategy: flags['strategy'],
67
84
  decomposeNestedPerms: flags['decompose-nested-permissions'],
85
+ manifest: flags['manifest'],
86
+ overrides,
68
87
  log: this.log.bind(this),
69
88
  });
70
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"decompose.js","sourceRoot":"","sources":["../../../src/commands/decomposer/decompose.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"decompose.js","sourceRoot":"","sources":["../../../src/commands/decomposer/decompose.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@ export default class DecomposerRecompose extends SfCommand<DecomposerResult> {
5
5
  static readonly description: string;
6
6
  static readonly examples: string[];
7
7
  static readonly flags: {
8
- 'metadata-type': import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
8
+ 'metadata-type': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ manifest: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
10
  postpurge: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
11
  'ignore-package-directory': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
12
  };
@@ -13,7 +13,13 @@ export default class DecomposerRecompose extends SfCommand {
13
13
  summary: messages.getMessage('flags.metadata-type.summary'),
14
14
  char: 'm',
15
15
  multiple: true,
16
- required: true,
16
+ required: false,
17
+ }),
18
+ manifest: Flags.file({
19
+ summary: messages.getMessage('flags.manifest.summary'),
20
+ char: 'x',
21
+ required: false,
22
+ exists: true,
17
23
  }),
18
24
  postpurge: Flags.boolean({
19
25
  summary: messages.getMessage('flags.postpurge.summary'),
@@ -29,10 +35,14 @@ export default class DecomposerRecompose extends SfCommand {
29
35
  };
30
36
  async run() {
31
37
  const { flags } = await this.parse(DecomposerRecompose);
38
+ if (!flags['metadata-type'] && !flags['manifest']) {
39
+ throw messages.createError('error.missingMetadataOrManifest');
40
+ }
32
41
  return recomposeMetadataTypes({
33
42
  metadataTypes: flags['metadata-type'],
34
43
  postpurge: flags['postpurge'],
35
44
  ignoreDirs: flags['ignore-package-directory'],
45
+ manifest: flags['manifest'],
36
46
  log: this.log.bind(this),
37
47
  });
38
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"recompose.js","sourceRoot":"","sources":["../../../src/commands/decomposer/recompose.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAG9E,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAAC;AAEhF,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,SAA2B;IACnE,MAAM,CAAmB,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAClE,MAAM,CAAmB,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1E,MAAM,CAAmB,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAErE,MAAM,CAAmB,KAAK,GAAG;QACtC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC;YAC5B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,6BAA6B,CAAC;YAC3D,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,IAAI;SACf,CAAC;QACF,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC;YACvB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,yBAAyB,CAAC;YACvD,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,KAAK;SACf,CAAC;QACF,0BAA0B,EAAE,KAAK,CAAC,SAAS,CAAC;YAC1C,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,wCAAwC,CAAC;YACtE,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,IAAI;SACf,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAExD,OAAO,sBAAsB,CAAC;YAC5B,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC;YACrC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC;YAC7B,UAAU,EAAE,KAAK,CAAC,0BAA0B,CAAC;YAC7C,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;SACzB,CAAC,CAAC;IACL,CAAC"}
1
+ {"version":3,"file":"recompose.js","sourceRoot":"","sources":["../../../src/commands/decomposer/recompose.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAG9E,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAAC;AAEhF,MAAM,CAAC,OAAO,OAAO,mBAAoB,SAAQ,SAA2B;IACnE,MAAM,CAAmB,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IAClE,MAAM,CAAmB,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAC1E,MAAM,CAAmB,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAErE,MAAM,CAAmB,KAAK,GAAG;QACtC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC;YAC5B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,6BAA6B,CAAC;YAC3D,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,KAAK;SAChB,CAAC;QACF,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC;YACnB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,wBAAwB,CAAC;YACtD,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,IAAI;SACb,CAAC;QACF,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC;YACvB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,yBAAyB,CAAC;YACvD,QAAQ,EAAE,KAAK;YACf,OAAO,EAAE,KAAK;SACf,CAAC;QACF,0BAA0B,EAAE,KAAK,CAAC,SAAS,CAAC;YAC1C,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,wCAAwC,CAAC;YACtE,IAAI,EAAE,GAAG;YACT,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,IAAI;SACf,CAAC;KACH,CAAC;IAEK,KAAK,CAAC,GAAG;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;QAExD,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC;YAClD,MAAM,QAAQ,CAAC,WAAW,CAAC,iCAAiC,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,sBAAsB,CAAC;YAC5B,aAAa,EAAE,KAAK,CAAC,eAAe,CAAC;YACrC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC;YAC7B,UAAU,EAAE,KAAK,CAAC,0BAA0B,CAAC;YAC7C,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC;YAC3B,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;SACzB,CAAC,CAAC;IACL,CAAC"}
@@ -1,25 +1,66 @@
1
1
  'use strict';
2
2
  import pLimit from 'p-limit';
3
3
  import { getRegistryValuesBySuffix } from '../metadata/getRegistryValuesBySuffix.js';
4
+ import { parseManifest } from '../metadata/parseManifest.js';
4
5
  import { decomposeFileHandler } from '../service/decompose/decomposeFileHandler.js';
5
6
  import { CONCURRENCY_LIMITS } from '../helpers/constants.js';
7
+ import { resolveDecomposeOptionsForType } from '../helpers/configOverrides.js';
6
8
  export async function decomposeMetadataTypes(options) {
7
- const { metadataTypes, prepurge, postpurge, format, ignoreDirs, strategy, decomposeNestedPerms, log } = options;
9
+ const { metadataTypes, prepurge, postpurge, format, ignoreDirs, strategy, decomposeNestedPerms, manifest, overrides, log, } = options;
10
+ let manifestFilter;
11
+ let effectiveTypes;
12
+ if (manifest) {
13
+ manifestFilter = await parseManifest(manifest, ignoreDirs);
14
+ if (metadataTypes && metadataTypes.length > 0) {
15
+ const manifestTypes = new Set(manifestFilter.suffixes);
16
+ effectiveTypes = metadataTypes.filter((type) => manifestTypes.has(type));
17
+ }
18
+ else {
19
+ effectiveTypes = manifestFilter.suffixes;
20
+ }
21
+ }
22
+ else {
23
+ if (!metadataTypes || metadataTypes.length === 0) {
24
+ throw Error('Either --metadata-type or --manifest must be provided.');
25
+ }
26
+ effectiveTypes = metadataTypes;
27
+ }
28
+ if (effectiveTypes.length === 0) {
29
+ log('No metadata types to decompose after applying the manifest filter.');
30
+ return { metadata: [] };
31
+ }
8
32
  // Limit concurrent metadata type processing to prevent file system overload
9
33
  const limit = pLimit(CONCURRENCY_LIMITS.METADATA_TYPES);
10
- const tasks = metadataTypes.map((metadataType) => limit(async () => {
11
- const { metaAttributes, ignorePath } = await getRegistryValuesBySuffix(metadataType, 'decompose', ignoreDirs);
12
- let effectiveStrategy = strategy;
13
- if (metadataType === 'labels' && strategy === 'grouped-by-tag') {
34
+ const processed = [];
35
+ const tasks = effectiveTypes.map((metadataType) => limit(async () => {
36
+ const manifestXmlPaths = manifestFilter?.parentXmlsBySuffix.get(metadataType);
37
+ let metaAttributes;
38
+ let ignorePath;
39
+ try {
40
+ ({ metaAttributes, ignorePath } = await getRegistryValuesBySuffix(metadataType, 'decompose', ignoreDirs));
41
+ }
42
+ catch (err) {
43
+ /* istanbul ignore if -- @preserve: preserves non-manifest behavior; unreachable via known CLI types */
44
+ if (!manifestFilter)
45
+ throw err;
46
+ /* istanbul ignore next -- @preserve: getRegistryValuesBySuffix always throws Error instances */
47
+ const message = err instanceof Error ? err.message : String(err);
48
+ log(`Skipping ${metadataType}: ${message}`);
49
+ return;
50
+ }
51
+ const resolved = resolveDecomposeOptionsForType(metadataType, { format, strategy, decomposeNestedPerms, prepurge, postpurge }, overrides);
52
+ let effectiveStrategy = resolved.strategy;
53
+ if (metadataType === 'labels' && effectiveStrategy === 'grouped-by-tag') {
14
54
  effectiveStrategy = 'unique-id';
15
55
  }
16
- if (metadataType === 'loyaltyProgramSetup' && strategy === 'grouped-by-tag') {
56
+ if (metadataType === 'loyaltyProgramSetup' && effectiveStrategy === 'grouped-by-tag') {
17
57
  effectiveStrategy = 'unique-id';
18
58
  }
19
- await decomposeFileHandler(metaAttributes, prepurge, postpurge, format, ignorePath, effectiveStrategy, decomposeNestedPerms);
59
+ await decomposeFileHandler(metaAttributes, resolved.prepurge, resolved.postpurge, resolved.format, ignorePath, effectiveStrategy, resolved.decomposeNestedPerms, manifestXmlPaths);
60
+ processed.push(metadataType);
20
61
  log(`All metadata files have been decomposed for the metadata type: ${metadataType}`);
21
62
  }));
22
63
  await Promise.all(tasks);
23
- return { metadata: metadataTypes };
64
+ return { metadata: processed };
24
65
  }
25
66
  //# sourceMappingURL=decomposeMetadataTypes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"decomposeMetadataTypes.js","sourceRoot":"","sources":["../../src/core/decomposeMetadataTypes.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAAyB;IACpE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,oBAAoB,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAEhH,4EAA4E;IAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAExD,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAC/C,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,MAAM,yBAAyB,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;QAC9G,IAAI,iBAAiB,GAAG,QAAQ,CAAC;QAEjC,IAAI,YAAY,KAAK,QAAQ,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;YAC/D,iBAAiB,GAAG,WAAW,CAAC;QAClC,CAAC;QAED,IAAI,YAAY,KAAK,qBAAqB,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;YAC5E,iBAAiB,GAAG,WAAW,CAAC;QAClC,CAAC;QAED,MAAM,oBAAoB,CACxB,cAAc,EACd,QAAQ,EACR,SAAS,EACT,MAAM,EACN,UAAU,EACV,iBAAiB,EACjB,oBAAoB,CACrB,CAAC;QAEF,GAAG,CAAC,kEAAkE,YAAY,EAAE,CAAC,CAAC;IACxF,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAEzB,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"decomposeMetadataTypes.js","sourceRoot":"","sources":["../../src/core/decomposeMetadataTypes.ts"],"names":[],"mappings":"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"}
@@ -1,20 +1,58 @@
1
1
  'use strict';
2
2
  import pLimit from 'p-limit';
3
3
  import { getRegistryValuesBySuffix } from '../metadata/getRegistryValuesBySuffix.js';
4
+ import { parseManifest } from '../metadata/parseManifest.js';
4
5
  import { recomposeFileHandler } from '../service/recompose/recomposeFileHandler.js';
5
6
  import { CONCURRENCY_LIMITS } from '../helpers/constants.js';
6
7
  export async function recomposeMetadataTypes(options) {
7
- const { metadataTypes, postpurge, ignoreDirs, log } = options;
8
+ const { metadataTypes, postpurge, ignoreDirs, manifest, log } = options;
9
+ let manifestFilter;
10
+ let effectiveTypes;
11
+ if (manifest) {
12
+ manifestFilter = await parseManifest(manifest, ignoreDirs);
13
+ if (metadataTypes && metadataTypes.length > 0) {
14
+ const manifestTypes = new Set(manifestFilter.suffixes);
15
+ effectiveTypes = metadataTypes.filter((type) => manifestTypes.has(type));
16
+ }
17
+ else {
18
+ effectiveTypes = manifestFilter.suffixes;
19
+ }
20
+ }
21
+ else {
22
+ if (!metadataTypes || metadataTypes.length === 0) {
23
+ throw Error('Either --metadata-type or --manifest must be provided.');
24
+ }
25
+ effectiveTypes = metadataTypes;
26
+ }
27
+ if (effectiveTypes.length === 0) {
28
+ log('No metadata types to recompose after applying the manifest filter.');
29
+ return { metadata: [] };
30
+ }
8
31
  // Limit concurrent metadata type processing to prevent file system overload
9
32
  const limit = pLimit(CONCURRENCY_LIMITS.METADATA_TYPES);
10
- const tasks = metadataTypes.map((metadataType) => limit(async () => {
11
- const { metaAttributes } = await getRegistryValuesBySuffix(metadataType, 'recompose', ignoreDirs);
12
- await recomposeFileHandler(metaAttributes, postpurge);
33
+ const processed = [];
34
+ const tasks = effectiveTypes.map((metadataType) => limit(async () => {
35
+ const manifestXmlPaths = manifestFilter?.parentXmlsBySuffix.get(metadataType);
36
+ let metaAttributes;
37
+ try {
38
+ ({ metaAttributes } = await getRegistryValuesBySuffix(metadataType, 'recompose', ignoreDirs));
39
+ }
40
+ catch (err) {
41
+ /* istanbul ignore if -- @preserve: preserves non-manifest behavior; unreachable via known CLI types */
42
+ if (!manifestFilter)
43
+ throw err;
44
+ /* istanbul ignore next -- @preserve: getRegistryValuesBySuffix always throws Error instances */
45
+ const message = err instanceof Error ? err.message : String(err);
46
+ log(`Skipping ${metadataType}: ${message}`);
47
+ return;
48
+ }
49
+ await recomposeFileHandler(metaAttributes, postpurge, manifestXmlPaths);
50
+ processed.push(metadataType);
13
51
  log(`All metadata files have been recomposed for the metadata type: ${metadataType}`);
14
52
  }));
15
53
  await Promise.all(tasks);
16
54
  return {
17
- metadata: metadataTypes,
55
+ metadata: processed,
18
56
  };
19
57
  }
20
58
  //# sourceMappingURL=recomposeMetadataTypes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"recomposeMetadataTypes.js","sourceRoot":"","sources":["../../src/core/recomposeMetadataTypes.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAAyB;IACpE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAE9D,4EAA4E;IAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAExD,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAC/C,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,yBAAyB,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;QAClG,MAAM,oBAAoB,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC;QACtD,GAAG,CAAC,kEAAkE,YAAY,EAAE,CAAC,CAAC;IACxF,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAEzB,OAAO;QACL,QAAQ,EAAE,aAAa;KACxB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"recomposeMetadataTypes.js","sourceRoot":"","sources":["../../src/core/recomposeMetadataTypes.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0CAA0C,CAAC;AACrF,OAAO,EAAE,aAAa,EAAkB,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAG7D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,OAAyB;IACpE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAExE,IAAI,cAA0C,CAAC;IAC/C,IAAI,cAAwB,CAAC;IAE7B,IAAI,QAAQ,EAAE,CAAC;QACb,cAAc,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC3D,IAAI,aAAa,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;YACvD,cAAc,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3E,CAAC;aAAM,CAAC;YACN,cAAc,GAAG,cAAc,CAAC,QAAQ,CAAC;QAC3C,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjD,MAAM,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACxE,CAAC;QACD,cAAc,GAAG,aAAa,CAAC;IACjC,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,GAAG,CAAC,oEAAoE,CAAC,CAAC;QAC1E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC1B,CAAC;IAED,4EAA4E;IAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAExD,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAChD,KAAK,CAAC,KAAK,IAAI,EAAE;QACf,MAAM,gBAAgB,GAAG,cAAc,EAAE,kBAAkB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAE9E,IAAI,cAAc,CAAC;QACnB,IAAI,CAAC;YACH,CAAC,EAAE,cAAc,EAAE,GAAG,MAAM,yBAAyB,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC;QAChG,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,uGAAuG;YACvG,IAAI,CAAC,cAAc;gBAAE,MAAM,GAAG,CAAC;YAC/B,gGAAgG;YAChG,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,GAAG,CAAC,YAAY,YAAY,KAAK,OAAO,EAAE,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,MAAM,oBAAoB,CAAC,cAAc,EAAE,SAAS,EAAE,gBAAgB,CAAC,CAAC;QACxE,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7B,GAAG,CAAC,kEAAkE,YAAY,EAAE,CAAC,CAAC;IACxF,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAEzB,OAAO;QACL,QAAQ,EAAE,SAAS;KACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { DecomposerOverride } from './types.js';
2
+ /**
3
+ * Resolve the absolute path of the default `.sfdecomposer.config.json`, located in the
4
+ * repo root (the nearest ancestor directory that contains `sfdx-project.json`). Throws
5
+ * a clear error when the repo root cannot be located or the config file does not exist.
6
+ */
7
+ export declare function resolveDefaultConfigPath(): Promise<string>;
8
+ export type ResolvedDecomposeTypeOptions = {
9
+ format: string;
10
+ strategy: string;
11
+ decomposeNestedPerms: boolean;
12
+ prepurge: boolean;
13
+ postpurge: boolean;
14
+ };
15
+ /**
16
+ * Load and validate the `overrides` array from a `.sfdecomposer.config.json` file.
17
+ * Returns an empty array if the file is missing, unreadable, or contains no overrides.
18
+ */
19
+ export declare function loadOverridesFromConfig(configPath: string): Promise<DecomposerOverride[]>;
20
+ /**
21
+ * Validate that the overrides array is well-formed. Throws on any structural problem.
22
+ * Unknown override keys are tolerated (ignored), but forbidden run-scope keys throw.
23
+ */
24
+ export declare function validateOverrides(overrides: DecomposerOverride[]): void;
25
+ /**
26
+ * Find the override (if any) that targets a specific metadata suffix.
27
+ */
28
+ export declare function getOverrideForType(metadataType: string, overrides?: DecomposerOverride[]): DecomposerOverride | undefined;
29
+ /**
30
+ * Resolve the effective decompose options for a single metadata type. The base values are
31
+ * the run-wide options (CLI flags or defaults); per-type override values, when present, win.
32
+ */
33
+ export declare function resolveDecomposeOptionsForType(metadataType: string, base: ResolvedDecomposeTypeOptions, overrides?: DecomposerOverride[]): ResolvedDecomposeTypeOptions;