sf-decomposer 6.11.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.
- package/CHANGELOG.md +7 -0
- package/README.md +82 -16
- package/lib/commands/decomposer/decompose.d.ts +1 -0
- package/lib/commands/decomposer/decompose.js +9 -0
- package/lib/commands/decomposer/decompose.js.map +1 -1
- package/lib/core/decomposeMetadataTypes.js +7 -5
- package/lib/core/decomposeMetadataTypes.js.map +1 -1
- package/lib/helpers/configOverrides.d.ts +33 -0
- package/lib/helpers/configOverrides.js +132 -0
- package/lib/helpers/configOverrides.js.map +1 -0
- package/lib/helpers/types.d.ts +10 -0
- package/lib/hooks/prerun.js +28 -25
- package/lib/hooks/prerun.js.map +1 -1
- package/lib/hooks/scopedPostRetrieve.js +33 -35
- package/lib/hooks/scopedPostRetrieve.js.map +1 -1
- package/lib/service/core/moveFiles.js +20 -8
- package/lib/service/core/moveFiles.js.map +1 -1
- package/messages/decomposer.decompose.md +4 -0
- package/oclif.manifest.json +9 -1
- package/package.json +1 -4
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,13 @@
|
|
|
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
|
+
|
|
8
15
|
## [6.11.0](https://github.com/mcarvin8/sf-decomposer/compare/v6.10.0...v6.11.0) (2026-04-24)
|
|
9
16
|
|
|
10
17
|
|
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ A Salesforce CLI plugin that **decomposes** large metadata XML files into smalle
|
|
|
26
26
|
- [Exceptions](#exceptions)
|
|
27
27
|
- [Troubleshooting](#troubleshooting)
|
|
28
28
|
- [Hooks](#hooks)
|
|
29
|
+
- [Per-Type Overrides](#per-type-overrides)
|
|
29
30
|
- [Ignore Files](#ignore-files)
|
|
30
31
|
- [.forceignore](#forceignore)
|
|
31
32
|
- [.sfdecomposerignore](#sfdecomposerignore)
|
|
@@ -78,7 +79,7 @@ A Salesforce CLI plugin that **decomposes** large metadata XML files into smalle
|
|
|
78
79
|
|
|
79
80
|
## Requirements
|
|
80
81
|
|
|
81
|
-
The [xml-disassembler](https://github.com/mcarvin8/xml-disassembler)
|
|
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:
|
|
82
83
|
|
|
83
84
|
| Platform | Architectures |
|
|
84
85
|
| ----------- | ---------------------------------- |
|
|
@@ -86,7 +87,7 @@ The [xml-disassembler](https://github.com/mcarvin8/xml-disassembler) NodeJS depe
|
|
|
86
87
|
| **Linux** | x64, arm64, ia32 |
|
|
87
88
|
| **Windows** | x64 |
|
|
88
89
|
|
|
89
|
-
If other platforms or architectures require support, please open an issue in
|
|
90
|
+
If other platforms or architectures require support, please open an issue in [xml-disassembler-node](https://github.com/mcarvin8/xml-disassembler-node/issues).
|
|
90
91
|
|
|
91
92
|
---
|
|
92
93
|
|
|
@@ -123,7 +124,7 @@ Decomposes metadata in all local package directories (from `sfdx-project.json`)
|
|
|
123
124
|
|
|
124
125
|
```
|
|
125
126
|
USAGE
|
|
126
|
-
$ sf decomposer decompose [-m <value>] [-x <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]
|
|
127
128
|
|
|
128
129
|
FLAGS
|
|
129
130
|
-m, --metadata-type=<value> Metadata suffix to process (e.g. flow, labels). Repeatable. Optional when --manifest is provided.
|
|
@@ -134,6 +135,7 @@ FLAGS
|
|
|
134
135
|
--prepurge Remove existing decomposed files before decomposing [default: false]
|
|
135
136
|
--postpurge Remove original metadata files after decomposing [default: false]
|
|
136
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]
|
|
137
139
|
|
|
138
140
|
GLOBAL FLAGS
|
|
139
141
|
--json Output as JSON.
|
|
@@ -357,18 +359,83 @@ Put **.sfdecomposer.config.json** in the project root to run:
|
|
|
357
359
|
- **After** `sf project retrieve start`: decompose.
|
|
358
360
|
- **Before** `sf project deploy start` / `sf project deploy validate`: recompose.
|
|
359
361
|
|
|
360
|
-
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.
|
|
361
363
|
|
|
362
|
-
| Option | Required | Description
|
|
363
|
-
| ---------------------------- | ----------- |
|
|
364
|
-
| `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.
|
|
365
|
-
| `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.
|
|
366
|
-
| `ignorePackageDirectories` | No | Comma-separated package directories to skip.
|
|
367
|
-
| `prePurge` | No | Remove existing decomposed files before decomposing (default: false).
|
|
368
|
-
| `postPurge` | No | After decompose: remove originals; after recompose: remove decomposed files (default: false).
|
|
369
|
-
| `decomposedFormat` | No | xml, json, json5, or yaml (default: xml).
|
|
370
|
-
| `strategy` | No | `unique-id` \| `grouped-by-tag` (default: unique-id).
|
|
371
|
-
| `decomposeNestedPermissions` | No | With grouped-by-tag, set true to further decompose permission set and muting permission set object/field permissions.
|
|
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.
|
|
437
|
+
|
|
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.
|
|
372
439
|
|
|
373
440
|
---
|
|
374
441
|
|
|
@@ -397,7 +464,6 @@ Bugs and feature requests: [open an issue](https://github.com/mcarvin8/sf-decomp
|
|
|
397
464
|
## Built With
|
|
398
465
|
|
|
399
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).
|
|
400
|
-
- [fs-extra](https://github.com/jprichardson/node-fs-extra) – Node.js: extra methods for the `fs` object like copy(), remove(), mkdirs().
|
|
401
467
|
- [@salesforce/source-deploy-retrieve](https://github.com/forcedotcom/source-deploy-retrieve) – JavaScript toolkit for working with Salesforce metadata.
|
|
402
468
|
|
|
403
469
|
---
|
|
@@ -408,4 +474,4 @@ Contributions are welcome. See [CONTRIBUTING.md](https://github.com/mcarvin8/sf-
|
|
|
408
474
|
|
|
409
475
|
## License
|
|
410
476
|
|
|
411
|
-
MIT
|
|
477
|
+
[MIT](https://raw.githubusercontent.com/mcarvin8/sf-decomposer/main/LICENSE.md)
|
|
@@ -13,6 +13,7 @@ export default class DecomposerDecompose extends SfCommand<DecomposerResult> {
|
|
|
13
13
|
'ignore-package-directory': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
14
|
strategy: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
15
|
'decompose-nested-permissions': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
config: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
17
|
};
|
|
17
18
|
run(): Promise<DecomposerResult>;
|
|
18
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 {
|
|
@@ -60,12 +61,19 @@ export default class DecomposerDecompose extends SfCommand {
|
|
|
60
61
|
required: false,
|
|
61
62
|
default: false,
|
|
62
63
|
}),
|
|
64
|
+
config: Flags.boolean({
|
|
65
|
+
summary: messages.getMessage('flags.config.summary'),
|
|
66
|
+
char: 'c',
|
|
67
|
+
required: false,
|
|
68
|
+
default: false,
|
|
69
|
+
}),
|
|
63
70
|
};
|
|
64
71
|
async run() {
|
|
65
72
|
const { flags } = await this.parse(DecomposerDecompose);
|
|
66
73
|
if (!flags['metadata-type'] && !flags['manifest']) {
|
|
67
74
|
throw messages.createError('error.missingMetadataOrManifest');
|
|
68
75
|
}
|
|
76
|
+
const overrides = flags['config'] ? await loadOverridesFromConfig(await resolveDefaultConfigPath()) : undefined;
|
|
69
77
|
return decomposeMetadataTypes({
|
|
70
78
|
metadataTypes: flags['metadata-type'],
|
|
71
79
|
prepurge: flags['prepurge'],
|
|
@@ -75,6 +83,7 @@ export default class DecomposerDecompose extends SfCommand {
|
|
|
75
83
|
strategy: flags['strategy'],
|
|
76
84
|
decomposeNestedPerms: flags['decompose-nested-permissions'],
|
|
77
85
|
manifest: flags['manifest'],
|
|
86
|
+
overrides,
|
|
78
87
|
log: this.log.bind(this),
|
|
79
88
|
});
|
|
80
89
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decompose.js","sourceRoot":"","sources":["../../../src/commands/decomposer/decompose.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,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;
|
|
1
|
+
{"version":3,"file":"decompose.js","sourceRoot":"","sources":["../../../src/commands/decomposer/decompose.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,9 @@ import { getRegistryValuesBySuffix } from '../metadata/getRegistryValuesBySuffix
|
|
|
4
4
|
import { parseManifest } from '../metadata/parseManifest.js';
|
|
5
5
|
import { decomposeFileHandler } from '../service/decompose/decomposeFileHandler.js';
|
|
6
6
|
import { CONCURRENCY_LIMITS } from '../helpers/constants.js';
|
|
7
|
+
import { resolveDecomposeOptionsForType } from '../helpers/configOverrides.js';
|
|
7
8
|
export async function decomposeMetadataTypes(options) {
|
|
8
|
-
const { metadataTypes, prepurge, postpurge, format, ignoreDirs, strategy, decomposeNestedPerms, manifest, log } = options;
|
|
9
|
+
const { metadataTypes, prepurge, postpurge, format, ignoreDirs, strategy, decomposeNestedPerms, manifest, overrides, log, } = options;
|
|
9
10
|
let manifestFilter;
|
|
10
11
|
let effectiveTypes;
|
|
11
12
|
if (manifest) {
|
|
@@ -47,14 +48,15 @@ export async function decomposeMetadataTypes(options) {
|
|
|
47
48
|
log(`Skipping ${metadataType}: ${message}`);
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
const resolved = resolveDecomposeOptionsForType(metadataType, { format, strategy, decomposeNestedPerms, prepurge, postpurge }, overrides);
|
|
52
|
+
let effectiveStrategy = resolved.strategy;
|
|
53
|
+
if (metadataType === 'labels' && effectiveStrategy === 'grouped-by-tag') {
|
|
52
54
|
effectiveStrategy = 'unique-id';
|
|
53
55
|
}
|
|
54
|
-
if (metadataType === 'loyaltyProgramSetup' &&
|
|
56
|
+
if (metadataType === 'loyaltyProgramSetup' && effectiveStrategy === 'grouped-by-tag') {
|
|
55
57
|
effectiveStrategy = 'unique-id';
|
|
56
58
|
}
|
|
57
|
-
await decomposeFileHandler(metaAttributes, prepurge, postpurge, format, ignorePath, effectiveStrategy, decomposeNestedPerms, manifestXmlPaths);
|
|
59
|
+
await decomposeFileHandler(metaAttributes, resolved.prepurge, resolved.postpurge, resolved.format, ignorePath, effectiveStrategy, resolved.decomposeNestedPerms, manifestXmlPaths);
|
|
58
60
|
processed.push(metadataType);
|
|
59
61
|
log(`All metadata files have been decomposed for the metadata type: ${metadataType}`);
|
|
60
62
|
}));
|
|
@@ -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,aAAa,EAAkB,MAAM,8BAA8B,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,MAAM,8CAA8C,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"decomposeMetadataTypes.js","sourceRoot":"","sources":["../../src/core/decomposeMetadataTypes.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
import { access, readFile } from 'node:fs/promises';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { getRepoRoot } from '../service/core/getRepoRoot.js';
|
|
5
|
+
import { DECOMPOSED_FILE_TYPES, DECOMPOSED_STRATEGIES, HOOK_CONFIG_JSON } from './constants.js';
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the absolute path of the default `.sfdecomposer.config.json`, located in the
|
|
8
|
+
* repo root (the nearest ancestor directory that contains `sfdx-project.json`). Throws
|
|
9
|
+
* a clear error when the repo root cannot be located or the config file does not exist.
|
|
10
|
+
*/
|
|
11
|
+
export async function resolveDefaultConfigPath() {
|
|
12
|
+
const { repoRoot } = await getRepoRoot();
|
|
13
|
+
/* istanbul ignore if -- @preserve: getRepoRoot throws when no sfdx-project.json ancestor exists, so repoRoot is always defined here. */
|
|
14
|
+
if (!repoRoot) {
|
|
15
|
+
throw new Error(`Cannot locate ${HOOK_CONFIG_JSON}: repo root not found.`);
|
|
16
|
+
}
|
|
17
|
+
const configPath = resolve(repoRoot, HOOK_CONFIG_JSON);
|
|
18
|
+
try {
|
|
19
|
+
await access(configPath);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new Error(`--config was provided but ${HOOK_CONFIG_JSON} was not found at ${configPath}. ` +
|
|
23
|
+
'Create the file in the repo root or omit --config.');
|
|
24
|
+
}
|
|
25
|
+
return configPath;
|
|
26
|
+
}
|
|
27
|
+
const ALLOWED_OVERRIDE_KEYS = new Set([
|
|
28
|
+
'metadataTypes',
|
|
29
|
+
'decomposedFormat',
|
|
30
|
+
'strategy',
|
|
31
|
+
'decomposeNestedPermissions',
|
|
32
|
+
'prePurge',
|
|
33
|
+
'postPurge',
|
|
34
|
+
]);
|
|
35
|
+
const FORBIDDEN_OVERRIDE_KEYS = new Set(['manifest', 'metadataSuffixes', 'ignorePackageDirectories']);
|
|
36
|
+
/**
|
|
37
|
+
* Load and validate the `overrides` array from a `.sfdecomposer.config.json` file.
|
|
38
|
+
* Returns an empty array if the file is missing, unreadable, or contains no overrides.
|
|
39
|
+
*/
|
|
40
|
+
export async function loadOverridesFromConfig(configPath) {
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = await readFile(configPath, 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(raw);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
/* istanbul ignore next -- @preserve: JSON.parse always throws SyntaxError instances. */
|
|
54
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
55
|
+
throw new Error(`Failed to parse ${configPath}: ${message}`);
|
|
56
|
+
}
|
|
57
|
+
const overrides = parsed.overrides;
|
|
58
|
+
if (!overrides)
|
|
59
|
+
return [];
|
|
60
|
+
if (!Array.isArray(overrides)) {
|
|
61
|
+
throw new Error(`"overrides" in ${configPath} must be an array.`);
|
|
62
|
+
}
|
|
63
|
+
validateOverrides(overrides);
|
|
64
|
+
return overrides;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validate that the overrides array is well-formed. Throws on any structural problem.
|
|
68
|
+
* Unknown override keys are tolerated (ignored), but forbidden run-scope keys throw.
|
|
69
|
+
*/
|
|
70
|
+
export function validateOverrides(overrides) {
|
|
71
|
+
const seenTypes = new Set();
|
|
72
|
+
for (let i = 0; i < overrides.length; i++) {
|
|
73
|
+
const override = overrides[i];
|
|
74
|
+
if (!override || typeof override !== 'object') {
|
|
75
|
+
throw new Error(`Override at index ${i} must be an object.`);
|
|
76
|
+
}
|
|
77
|
+
if (!Array.isArray(override.metadataTypes) || override.metadataTypes.length === 0) {
|
|
78
|
+
throw new Error(`Override at index ${i} must include a non-empty "metadataTypes" array.`);
|
|
79
|
+
}
|
|
80
|
+
for (const key of Object.keys(override)) {
|
|
81
|
+
if (FORBIDDEN_OVERRIDE_KEYS.has(key)) {
|
|
82
|
+
throw new Error(`Override at index ${i} contains "${key}", which is a run-scope option and cannot be set per metadata type.`);
|
|
83
|
+
}
|
|
84
|
+
if (!ALLOWED_OVERRIDE_KEYS.has(key)) {
|
|
85
|
+
// Unknown keys are ignored to keep the config forward-compatible.
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (override.decomposedFormat !== undefined && !DECOMPOSED_FILE_TYPES.includes(override.decomposedFormat)) {
|
|
90
|
+
throw new Error(`Override at index ${i} has invalid "decomposedFormat": "${override.decomposedFormat}". ` +
|
|
91
|
+
`Allowed values: ${DECOMPOSED_FILE_TYPES.join(', ')}.`);
|
|
92
|
+
}
|
|
93
|
+
if (override.strategy !== undefined && !DECOMPOSED_STRATEGIES.includes(override.strategy)) {
|
|
94
|
+
throw new Error(`Override at index ${i} has invalid "strategy": "${override.strategy}". ` +
|
|
95
|
+
`Allowed values: ${DECOMPOSED_STRATEGIES.join(', ')}.`);
|
|
96
|
+
}
|
|
97
|
+
for (const metadataType of override.metadataTypes) {
|
|
98
|
+
if (typeof metadataType !== 'string' || metadataType.trim() === '') {
|
|
99
|
+
throw new Error(`Override at index ${i} contains an empty or non-string metadata type.`);
|
|
100
|
+
}
|
|
101
|
+
if (seenTypes.has(metadataType)) {
|
|
102
|
+
throw new Error(`Metadata type "${metadataType}" appears in more than one override. Each type may appear at most once.`);
|
|
103
|
+
}
|
|
104
|
+
seenTypes.add(metadataType);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Find the override (if any) that targets a specific metadata suffix.
|
|
110
|
+
*/
|
|
111
|
+
export function getOverrideForType(metadataType, overrides) {
|
|
112
|
+
if (!overrides || overrides.length === 0)
|
|
113
|
+
return undefined;
|
|
114
|
+
return overrides.find((override) => override.metadataTypes.includes(metadataType));
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Resolve the effective decompose options for a single metadata type. The base values are
|
|
118
|
+
* the run-wide options (CLI flags or defaults); per-type override values, when present, win.
|
|
119
|
+
*/
|
|
120
|
+
export function resolveDecomposeOptionsForType(metadataType, base, overrides) {
|
|
121
|
+
const override = getOverrideForType(metadataType, overrides);
|
|
122
|
+
if (!override)
|
|
123
|
+
return base;
|
|
124
|
+
return {
|
|
125
|
+
format: override.decomposedFormat ?? base.format,
|
|
126
|
+
strategy: override.strategy ?? base.strategy,
|
|
127
|
+
decomposeNestedPerms: override.decomposeNestedPermissions ?? base.decomposeNestedPerms,
|
|
128
|
+
prepurge: override.prePurge ?? base.prepurge,
|
|
129
|
+
postpurge: override.postPurge ?? base.postpurge,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=configOverrides.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configOverrides.js","sourceRoot":"","sources":["../../src/helpers/configOverrides.ts"],"names":[],"mappings":"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"}
|
package/lib/helpers/types.d.ts
CHANGED
|
@@ -3,6 +3,14 @@ import { ScopedPostRetrieve } from '@salesforce/source-deploy-retrieve';
|
|
|
3
3
|
export type DecomposerResult = {
|
|
4
4
|
metadata: string[];
|
|
5
5
|
};
|
|
6
|
+
export type DecomposerOverride = {
|
|
7
|
+
metadataTypes: string[];
|
|
8
|
+
decomposedFormat?: string;
|
|
9
|
+
strategy?: string;
|
|
10
|
+
decomposeNestedPermissions?: boolean;
|
|
11
|
+
prePurge?: boolean;
|
|
12
|
+
postPurge?: boolean;
|
|
13
|
+
};
|
|
6
14
|
export type ConfigFile = {
|
|
7
15
|
metadataSuffixes: string;
|
|
8
16
|
prePurge: boolean;
|
|
@@ -12,6 +20,7 @@ export type ConfigFile = {
|
|
|
12
20
|
strategy: string;
|
|
13
21
|
decomposeNestedPermissions: boolean;
|
|
14
22
|
manifest?: string;
|
|
23
|
+
overrides?: DecomposerOverride[];
|
|
15
24
|
};
|
|
16
25
|
export type SfdxProject = {
|
|
17
26
|
packageDirectories: Array<{
|
|
@@ -46,6 +55,7 @@ export type DecomposeOptions = {
|
|
|
46
55
|
strategy: string;
|
|
47
56
|
decomposeNestedPerms: boolean;
|
|
48
57
|
manifest?: string;
|
|
58
|
+
overrides?: DecomposerOverride[];
|
|
49
59
|
log: (msg: string) => void;
|
|
50
60
|
};
|
|
51
61
|
export type RecomposeOptions = {
|
package/lib/hooks/prerun.js
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import
|
|
4
|
+
import { recomposeMetadataTypes } from '../core/recomposeMetadataTypes.js';
|
|
5
5
|
import { getRepoRoot } from '../service/core/getRepoRoot.js';
|
|
6
6
|
import { HOOK_CONFIG_JSON } from '../helpers/constants.js';
|
|
7
|
-
function
|
|
8
|
-
const
|
|
9
|
-
const postpurge = configFile.postPurge || false;
|
|
7
|
+
function buildRecomposeOptions(configFile, log) {
|
|
8
|
+
const metadataSuffixes = configFile.metadataSuffixes || '.';
|
|
10
9
|
const ignorePackageDirs = configFile.ignorePackageDirectories || '';
|
|
11
10
|
const manifest = configFile.manifest ?? '';
|
|
12
|
-
if (
|
|
11
|
+
if (metadataSuffixes.trim() === '.' && manifest.trim() === '') {
|
|
13
12
|
return undefined;
|
|
14
13
|
}
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
14
|
+
const metadataTypes = metadataSuffixes.trim() !== '.'
|
|
15
|
+
? metadataSuffixes
|
|
16
|
+
.split(',')
|
|
17
|
+
.map((type) => type.replace(/,/g, '').trim())
|
|
18
|
+
.filter((type) => type.length > 0)
|
|
19
|
+
: undefined;
|
|
20
|
+
const ignoreDirs = ignorePackageDirs.trim() !== ''
|
|
21
|
+
? ignorePackageDirs
|
|
22
|
+
.split(',')
|
|
23
|
+
.map((dir) => dir.replace(/,/g, '').trim())
|
|
24
|
+
.filter((dir) => dir.length > 0)
|
|
25
|
+
: undefined;
|
|
26
|
+
return {
|
|
27
|
+
metadataTypes,
|
|
28
|
+
postpurge: configFile.postPurge || false,
|
|
29
|
+
ignoreDirs,
|
|
30
|
+
manifest: manifest.trim() !== '' ? manifest.trim() : undefined,
|
|
31
|
+
log,
|
|
32
|
+
};
|
|
32
33
|
}
|
|
33
34
|
export const prerun = async function (options) {
|
|
34
35
|
if (!['project:deploy:validate', 'project:deploy:start'].includes(options.Command.id)) {
|
|
@@ -47,9 +48,11 @@ export const prerun = async function (options) {
|
|
|
47
48
|
catch (error) {
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
|
-
const
|
|
51
|
-
|
|
51
|
+
const recomposeOptions = buildRecomposeOptions(configFile, (msg) => {
|
|
52
|
+
this.log(msg);
|
|
53
|
+
});
|
|
54
|
+
if (!recomposeOptions)
|
|
52
55
|
return;
|
|
53
|
-
await
|
|
56
|
+
await recomposeMetadataTypes(recomposeOptions);
|
|
54
57
|
};
|
|
55
58
|
//# sourceMappingURL=prerun.js.map
|
package/lib/hooks/prerun.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerun.js","sourceRoot":"","sources":["../../src/hooks/prerun.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,
|
|
1
|
+
{"version":3,"file":"prerun.js","sourceRoot":"","sources":["../../src/hooks/prerun.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,SAAS,qBAAqB,CAC5B,UAAsB,EACtB,GAA0B;IAE1B,MAAM,gBAAgB,GAAW,UAAU,CAAC,gBAAgB,IAAI,GAAG,CAAC;IACpE,MAAM,iBAAiB,GAAW,UAAU,CAAC,wBAAwB,IAAI,EAAE,CAAC;IAC5E,MAAM,QAAQ,GAAW,UAAU,CAAC,QAAQ,IAAI,EAAE,CAAC;IAEnD,IAAI,gBAAgB,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9D,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,aAAa,GACjB,gBAAgB,CAAC,IAAI,EAAE,KAAK,GAAG;QAC7B,CAAC,CAAC,gBAAgB;aACb,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;aAC5C,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACtC,CAAC,CAAC,SAAS,CAAC;IAEhB,MAAM,UAAU,GACd,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE;QAC7B,CAAC,CAAC,iBAAiB;aACd,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;aAC1C,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QACpC,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,aAAa;QACb,SAAS,EAAE,UAAU,CAAC,SAAS,IAAI,KAAK;QACxC,UAAU;QACV,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS;QAC9D,GAAG;KACJ,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAmB,KAAK,WAAW,OAAO;IAC3D,IAAI,CAAC,CAAC,yBAAyB,EAAE,sBAAsB,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;QACtF,OAAO;IACT,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;IACzC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IACD,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAEvD,IAAI,UAAsB,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,UAAU,GAAW,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC/D,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAe,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,UAAU,EAAE,CAAC,GAAW,EAAE,EAAE;QACzE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,gBAAgB;QAAE,OAAO;IAE9B,MAAM,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;AACjD,CAAC,CAAC"}
|
|
@@ -1,44 +1,40 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
|
-
import
|
|
4
|
+
import { decomposeMetadataTypes } from '../core/decomposeMetadataTypes.js';
|
|
5
5
|
import { getRepoRoot } from '../service/core/getRepoRoot.js';
|
|
6
6
|
import { HOOK_CONFIG_JSON } from '../helpers/constants.js';
|
|
7
|
-
function
|
|
8
|
-
const
|
|
9
|
-
const format = configFile.decomposedFormat || 'xml';
|
|
10
|
-
const prepurge = configFile.prePurge || false;
|
|
11
|
-
const postpurge = configFile.postPurge || false;
|
|
7
|
+
function buildDecomposeOptions(configFile, log) {
|
|
8
|
+
const metadataSuffixes = configFile.metadataSuffixes || '.';
|
|
12
9
|
const ignorePackageDirs = configFile.ignorePackageDirectories || '';
|
|
13
|
-
const strategy = configFile.strategy || 'unique-id';
|
|
14
|
-
const decomposeNestedPermissions = configFile.decomposeNestedPermissions || false;
|
|
15
10
|
const manifest = configFile.manifest ?? '';
|
|
16
|
-
if (
|
|
11
|
+
if (metadataSuffixes.trim() === '.' && manifest.trim() === '') {
|
|
17
12
|
return undefined;
|
|
18
13
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
14
|
+
const metadataTypes = metadataSuffixes.trim() !== '.'
|
|
15
|
+
? metadataSuffixes
|
|
16
|
+
.split(',')
|
|
17
|
+
.map((type) => type.replace(/,/g, '').trim())
|
|
18
|
+
.filter((type) => type.length > 0)
|
|
19
|
+
: undefined;
|
|
20
|
+
const ignoreDirs = ignorePackageDirs.trim() !== ''
|
|
21
|
+
? ignorePackageDirs
|
|
22
|
+
.split(',')
|
|
23
|
+
.map((dir) => dir.replace(/,/g, '').trim())
|
|
24
|
+
.filter((dir) => dir.length > 0)
|
|
25
|
+
: undefined;
|
|
26
|
+
return {
|
|
27
|
+
metadataTypes,
|
|
28
|
+
prepurge: configFile.prePurge || false,
|
|
29
|
+
postpurge: configFile.postPurge || false,
|
|
30
|
+
format: configFile.decomposedFormat || 'xml',
|
|
31
|
+
ignoreDirs,
|
|
32
|
+
strategy: configFile.strategy || 'unique-id',
|
|
33
|
+
decomposeNestedPerms: configFile.decomposeNestedPermissions || false,
|
|
34
|
+
manifest: manifest.trim() !== '' ? manifest.trim() : undefined,
|
|
35
|
+
overrides: configFile.overrides,
|
|
36
|
+
log,
|
|
37
|
+
};
|
|
42
38
|
}
|
|
43
39
|
export const scopedPostRetrieve = async function (options) {
|
|
44
40
|
if (!options.result?.retrieveResult.response.status) {
|
|
@@ -57,9 +53,11 @@ export const scopedPostRetrieve = async function (options) {
|
|
|
57
53
|
catch (error) {
|
|
58
54
|
return;
|
|
59
55
|
}
|
|
60
|
-
const
|
|
61
|
-
|
|
56
|
+
const decomposeOptions = buildDecomposeOptions(configFile, (msg) => {
|
|
57
|
+
this.log(msg);
|
|
58
|
+
});
|
|
59
|
+
if (!decomposeOptions)
|
|
62
60
|
return;
|
|
63
|
-
await
|
|
61
|
+
await decomposeMetadataTypes(decomposeOptions);
|
|
64
62
|
};
|
|
65
63
|
//# sourceMappingURL=scopedPostRetrieve.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scopedPostRetrieve.js","sourceRoot":"","sources":["../../src/hooks/scopedPostRetrieve.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,
|
|
1
|
+
{"version":3,"file":"scopedPostRetrieve.js","sourceRoot":"","sources":["../../src/hooks/scopedPostRetrieve.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
import { readdir, stat } from 'node:fs/promises';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
import { move } from 'fs-extra';
|
|
2
|
+
import { readdir, stat, rename, copyFile, unlink, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
5
4
|
import pLimit from 'p-limit';
|
|
6
5
|
import { CONCURRENCY_LIMITS } from '../../helpers/constants.js';
|
|
6
|
+
async function moveFile(source, destination) {
|
|
7
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
8
|
+
try {
|
|
9
|
+
await rename(source, destination);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
const code = err.code;
|
|
13
|
+
// EXDEV: cross-device rename. EPERM/EEXIST: Windows rename when destination exists.
|
|
14
|
+
if (code === 'EXDEV' || code === 'EPERM' || code === 'EEXIST') {
|
|
15
|
+
await copyFile(source, destination);
|
|
16
|
+
await unlink(source);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
7
23
|
export async function moveFiles(sourceDirectory, destinationDirectory, predicate) {
|
|
8
24
|
const files = await readdir(sourceDirectory);
|
|
9
25
|
// Limit concurrent stat operations
|
|
@@ -17,11 +33,7 @@ export async function moveFiles(sourceDirectory, destinationDirectory, predicate
|
|
|
17
33
|
const moveLimit = pLimit(CONCURRENCY_LIMITS.FILE_OPERATIONS);
|
|
18
34
|
const moveTasks = fileStats
|
|
19
35
|
.filter(({ isFile, shouldMove }) => isFile && shouldMove)
|
|
20
|
-
.map(({ file }) => moveLimit(() =>
|
|
21
|
-
const sourceFile = join(sourceDirectory, file);
|
|
22
|
-
const destinationFile = join(destinationDirectory, file);
|
|
23
|
-
return move(sourceFile, destinationFile, { overwrite: true });
|
|
24
|
-
}));
|
|
36
|
+
.map(({ file }) => moveLimit(() => moveFile(join(sourceDirectory, file), join(destinationDirectory, file))));
|
|
25
37
|
await Promise.all(moveTasks);
|
|
26
38
|
}
|
|
27
39
|
//# sourceMappingURL=moveFiles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"moveFiles.js","sourceRoot":"","sources":["../../../src/service/core/moveFiles.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"moveFiles.js","sourceRoot":"","sources":["../../../src/service/core/moveFiles.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,MAAM,MAAM,SAAS,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,KAAK,UAAU,QAAQ,CAAC,MAAc,EAAE,WAAmB;IACzD,MAAM,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,oFAAoF;QACpF,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC9D,MAAM,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YACpC,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,eAAuB,EACvB,oBAA4B,EAC5B,SAAwC;IAExC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC,CAAC;IAE7C,mCAAmC;IACnC,MAAM,SAAS,GAAG,MAAM,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,GAAG,CACjC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACjB,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACrB,IAAI;QACJ,MAAM,EAAE,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE;QAC1D,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC;KAC5B,CAAC,CAAC,CACJ,CACF,CAAC;IAEF,wCAAwC;IACxC,MAAM,SAAS,GAAG,MAAM,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAC7D,MAAM,SAAS,GAAG,SAAS;SACxB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,MAAM,IAAI,UAAU,CAAC;SACxD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/G,MAAM,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -48,6 +48,10 @@ Strategy to follow when decomposing files.
|
|
|
48
48
|
|
|
49
49
|
Additionally decompose object and field permissions on a permission set when strategy is set to "grouped-by-tag".
|
|
50
50
|
|
|
51
|
+
# flags.config.summary
|
|
52
|
+
|
|
53
|
+
Load per-metadata-type overrides from .sfdecomposer.config.json in the repo root. When set, the file's "overrides" array is applied (format, strategy, decomposeNestedPermissions, prePurge, postPurge per type). Other top-level config fields are ignored when invoking the CLI directly.
|
|
54
|
+
|
|
51
55
|
# error.missingMetadataOrManifest
|
|
52
56
|
|
|
53
57
|
Either --metadata-type (-m) or --manifest (-x) must be provided.
|
package/oclif.manifest.json
CHANGED
|
@@ -105,6 +105,14 @@
|
|
|
105
105
|
"summary": "Additionally decompose object and field permissions on a permission set when strategy is set to \"grouped-by-tag\".",
|
|
106
106
|
"allowNo": false,
|
|
107
107
|
"type": "boolean"
|
|
108
|
+
},
|
|
109
|
+
"config": {
|
|
110
|
+
"char": "c",
|
|
111
|
+
"name": "config",
|
|
112
|
+
"required": false,
|
|
113
|
+
"summary": "Load per-metadata-type overrides from .sfdecomposer.config.json in the repo root. When set, the file's \"overrides\" array is applied (format, strategy, decomposeNestedPermissions, prePurge, postPurge per type). Other top-level config fields are ignored when invoking the CLI directly.",
|
|
114
|
+
"allowNo": false,
|
|
115
|
+
"type": "boolean"
|
|
108
116
|
}
|
|
109
117
|
},
|
|
110
118
|
"hasDynamicHelp": false,
|
|
@@ -213,5 +221,5 @@
|
|
|
213
221
|
]
|
|
214
222
|
}
|
|
215
223
|
},
|
|
216
|
-
"version": "6.
|
|
224
|
+
"version": "6.12.0"
|
|
217
225
|
}
|
package/package.json
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sf-decomposer",
|
|
3
3
|
"description": "Split large Salesforce metadata files into version-control-friendly pieces and rebuild deployment-ready files.",
|
|
4
|
-
"version": "6.
|
|
4
|
+
"version": "6.12.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@oclif/core": "^4",
|
|
7
7
|
"@salesforce/core": "^8.26.3",
|
|
8
8
|
"@salesforce/sf-plugins-core": "^12.2.6",
|
|
9
9
|
"@salesforce/source-deploy-retrieve": "^12.34.1",
|
|
10
|
-
"fs-extra": "^11.3.3",
|
|
11
10
|
"p-limit": "^7.3.0",
|
|
12
11
|
"xml-disassembler": "^2.4.0"
|
|
13
12
|
},
|
|
14
13
|
"devDependencies": {
|
|
15
|
-
"@commitlint/cli": "^20.4.2",
|
|
16
14
|
"@commitlint/config-conventional": "^20.4.2",
|
|
17
15
|
"@oclif/plugin-command-snapshot": "^5.3.10",
|
|
18
16
|
"@salesforce/cli-plugins-testkit": "^5.3.39",
|
|
19
17
|
"@salesforce/dev-config": "^4.3.3",
|
|
20
18
|
"@salesforce/prettier-config": "^0.0.4",
|
|
21
|
-
"@types/fs-extra": "^11.0.4",
|
|
22
19
|
"@types/node": "20",
|
|
23
20
|
"@vitest/coverage-v8": "^4.1.5",
|
|
24
21
|
"eslint-config-salesforce-typescript": "^4.0.1",
|