sf-git-merge-driver 1.0.0-dev-3.13704714225-2
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/LICENSE.md +9 -0
- package/README.md +74 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +7 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +7 -0
- package/lib/commands/git/merge/driver/install.d.ts +8 -0
- package/lib/commands/git/merge/driver/install.js +21 -0
- package/lib/commands/git/merge/driver/install.js.map +1 -0
- package/lib/commands/git/merge/driver/uninstall.d.ts +8 -0
- package/lib/commands/git/merge/driver/uninstall.js +15 -0
- package/lib/commands/git/merge/driver/uninstall.js.map +1 -0
- package/lib/constant/driverConstant.d.ts +1 -0
- package/lib/constant/driverConstant.js +2 -0
- package/lib/constant/driverConstant.js.map +1 -0
- package/lib/driver/MergeDriver.d.ts +3 -0
- package/lib/driver/MergeDriver.js +17 -0
- package/lib/driver/MergeDriver.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +18 -0
- package/lib/index.js.map +1 -0
- package/lib/merger/JsonMerger.d.ts +14 -0
- package/lib/merger/JsonMerger.js +90 -0
- package/lib/merger/JsonMerger.js.map +1 -0
- package/lib/merger/XmlMerger.d.ts +3 -0
- package/lib/merger/XmlMerger.js +32 -0
- package/lib/merger/XmlMerger.js.map +1 -0
- package/lib/service/installService.d.ts +3 -0
- package/lib/service/installService.js +24 -0
- package/lib/service/installService.js.map +1 -0
- package/lib/service/uninstallService.d.ts +3 -0
- package/lib/service/uninstallService.js +29 -0
- package/lib/service/uninstallService.js.map +1 -0
- package/messages/install.md +13 -0
- package/messages/uninstall.md +13 -0
- package/npm-shrinkwrap.json +14069 -0
- package/oclif.manifest.json +145 -0
- package/package.json +255 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Sebastien Colladon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Salesforce Metadata Git Merge Driver
|
|
2
|
+
|
|
3
|
+
A custom Git merge driver designed specifically for Salesforce metadata files. This tool helps resolve merge conflicts in Salesforce XML metadata files by understanding their structure and intelligently merging changes.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Intelligent merging of Salesforce XML metadata files
|
|
8
|
+
- Handles complex metadata structures like arrays with unique identifiers
|
|
9
|
+
- Supports both local and global installation
|
|
10
|
+
- Easy to use with SFDX CLI plugin commands
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
### As SFDX Plugin
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
sf plugins install sf-git-merge-driver
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Local Repository Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
sf git merge driver install
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This will:
|
|
27
|
+
- Configure your Git settings to use the merge driver
|
|
28
|
+
- Add appropriate entries to your `.gitattributes` file
|
|
29
|
+
- Set up the driver to handle XML files
|
|
30
|
+
|
|
31
|
+
## Uninstallation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
sf git merge driver uninstall
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## How It Works
|
|
38
|
+
|
|
39
|
+
The merge driver works by:
|
|
40
|
+
1. Converting XML to JSON for easier processing
|
|
41
|
+
2. Using a specialized three-way merge algorithm that understands Salesforce metadata structures
|
|
42
|
+
3. Intelligently resolving conflicts based on metadata type
|
|
43
|
+
4. Converting the merged result back to properly formatted XML
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
The driver is configured to work with `.xml` files by default. The installation adds the following to your `.gitattributes` file:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
*.xml merge=salesforce-source
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Changelog
|
|
54
|
+
|
|
55
|
+
[changelog.md](CHANGELOG.md) is available for consultation.
|
|
56
|
+
|
|
57
|
+
## Versioning
|
|
58
|
+
|
|
59
|
+
Versioning follows [SemVer](http://semver.org/) specification.
|
|
60
|
+
|
|
61
|
+
## Authors
|
|
62
|
+
|
|
63
|
+
- **Kevin Gossent** - [yohanim](https://github.com/yohanim)
|
|
64
|
+
- **Sebastien Colladon** - [scolladon](https://github.com/scolladon)
|
|
65
|
+
|
|
66
|
+
## Contributing
|
|
67
|
+
|
|
68
|
+
Contributions are what make the trailblazer community such an amazing place. I regard this component as a way to inspire and learn from others. Any contributions you make are **appreciated**.
|
|
69
|
+
|
|
70
|
+
See [contributing.md](CONTRIBUTING.md) for sgd contribution principles.
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
This project license is MIT - see the [LICENSE.md](LICENSE.md) file for details
|
package/bin/dev.cmd
ADDED
package/bin/dev.js
ADDED
package/bin/run.cmd
ADDED
package/bin/run.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
|
+
export default class Install extends SfCommand<void> {
|
|
3
|
+
static readonly summary: string;
|
|
4
|
+
static readonly description: string;
|
|
5
|
+
static readonly examples: string[];
|
|
6
|
+
static readonly flags: {};
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Messages } from '@salesforce/core';
|
|
2
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
3
|
+
import { InstallService } from '../../../../service/installService.js';
|
|
4
|
+
import { UninstallService } from '../../../../service/uninstallService.js';
|
|
5
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
6
|
+
const messages = Messages.loadMessages('sf-git-merge-driver', 'install');
|
|
7
|
+
export default class Install extends SfCommand {
|
|
8
|
+
static summary = messages.getMessage('summary');
|
|
9
|
+
static description = messages.getMessage('description');
|
|
10
|
+
static examples = messages.getMessages('examples');
|
|
11
|
+
static flags = {};
|
|
12
|
+
async run() {
|
|
13
|
+
try {
|
|
14
|
+
await new UninstallService().uninstallMergeDriver();
|
|
15
|
+
// biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
await new InstallService().installMergeDriver();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../../../../src/commands/git/merge/driver/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAA;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAE1E,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAA;AAExE,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,SAAe;IAC3C,MAAM,CAAmB,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;IACjE,MAAM,CAAmB,WAAW,GACzC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;IAC7B,MAAM,CAAmB,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;IAEpE,MAAM,CAAmB,KAAK,GAAG,EAAE,CAAA;IAEnC,KAAK,CAAC,GAAG;QACd,IAAI,CAAC;YACH,MAAM,IAAI,gBAAgB,EAAE,CAAC,oBAAoB,EAAE,CAAA;YACnD,qEAAqE;QACvE,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,MAAM,IAAI,cAAc,EAAE,CAAC,kBAAkB,EAAE,CAAA;IACjD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
|
+
export default class Uninstall extends SfCommand<void> {
|
|
3
|
+
static readonly summary: string;
|
|
4
|
+
static readonly description: string;
|
|
5
|
+
static readonly examples: string[];
|
|
6
|
+
static readonly flags: {};
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Messages } from '@salesforce/core';
|
|
2
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
3
|
+
import { UninstallService } from '../../../../service/uninstallService.js';
|
|
4
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
5
|
+
const messages = Messages.loadMessages('sf-git-merge-driver', 'uninstall');
|
|
6
|
+
export default class Uninstall extends SfCommand {
|
|
7
|
+
static summary = messages.getMessage('summary');
|
|
8
|
+
static description = messages.getMessage('description');
|
|
9
|
+
static examples = messages.getMessages('examples');
|
|
10
|
+
static flags = {};
|
|
11
|
+
async run() {
|
|
12
|
+
await new UninstallService().uninstallMergeDriver();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=uninstall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../../../../src/commands/git/merge/driver/uninstall.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAA;AAE1E,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC5D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,qBAAqB,EAAE,WAAW,CAAC,CAAA;AAE1E,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,SAAe;IAC7C,MAAM,CAAmB,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;IACjE,MAAM,CAAmB,WAAW,GACzC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;IAC7B,MAAM,CAAmB,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;IAEpE,MAAM,CAAmB,KAAK,GAAG,EAAE,CAAA;IAEnC,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,gBAAgB,EAAE,CAAC,oBAAoB,EAAE,CAAA;IACrD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DRIVER_NAME = "salesforce-source";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driverConstant.js","sourceRoot":"","sources":["../../src/constant/driverConstant.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { XmlMerger } from '../merger/XmlMerger.js';
|
|
3
|
+
export class MergeDriver {
|
|
4
|
+
async mergeFiles(ancestorFile, ourFile, theirFile, outputFile) {
|
|
5
|
+
// Read all three versions
|
|
6
|
+
const [ancestorContent, ourContent, theirContent] = await Promise.all([
|
|
7
|
+
readFile(ancestorFile, 'utf8'),
|
|
8
|
+
readFile(ourFile, 'utf8'),
|
|
9
|
+
readFile(theirFile, 'utf8'),
|
|
10
|
+
]);
|
|
11
|
+
const xmlMerger = new XmlMerger();
|
|
12
|
+
const mergedContent = await xmlMerger.tripartXmlMerge(ancestorContent, ourContent, theirContent);
|
|
13
|
+
// Write the merged content to the output file
|
|
14
|
+
await writeFile(outputFile, mergedContent);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=MergeDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MergeDriver.js","sourceRoot":"","sources":["../../src/driver/MergeDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAElD,MAAM,OAAO,WAAW;IACtB,KAAK,CAAC,UAAU,CAAC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU;QAC3D,0BAA0B;QAC1B,MAAM,CAAC,eAAe,EAAE,UAAU,EAAE,YAAY,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YACpE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;YAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;SAC5B,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAA;QAEjC,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,eAAe,CACnD,eAAe,EACf,UAAU,EACV,YAAY,CACb,CAAA;QAED,8CAA8C;QAC9C,MAAM,SAAS,CAAC,UAAU,EAAE,aAAa,CAAC,CAAA;IAC5C,CAAC;CACF"}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env -S NODE_OPTIONS="--no-warnings=ExperimentalWarning" npx ts-node --project tsconfig.json --esm
|
|
2
|
+
import { MergeDriver } from './driver/MergeDriver.js';
|
|
3
|
+
if (process.argv.length >= 6) {
|
|
4
|
+
const [, , ancestorFile, ourFile, theirFile, outputFile] = process.argv;
|
|
5
|
+
const mergeDriver = new MergeDriver();
|
|
6
|
+
mergeDriver
|
|
7
|
+
.mergeFiles(ancestorFile, ourFile, theirFile, outputFile)
|
|
8
|
+
.then(() => process.exit(0));
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
console.error('Usage: sf-git-merge-driver %O %A %B %P');
|
|
12
|
+
console.error(' %O: ancestor file');
|
|
13
|
+
console.error(' %A: our file');
|
|
14
|
+
console.error(' %B: their file');
|
|
15
|
+
console.error(' %P: output file path');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAErD,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,AAAD,EAAG,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAA;IACvE,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAA;IACrC,WAAW;SACR,UAAU,CAAC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC;SACxD,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AAChC,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAA;IACvD,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAA;IACpC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IAC/B,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACjC,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
|
|
2
|
+
interface JsonObject {
|
|
3
|
+
[key: string]: JsonValue;
|
|
4
|
+
}
|
|
5
|
+
interface JsonArray extends Array<JsonValue> {
|
|
6
|
+
}
|
|
7
|
+
export declare class JsonMerger {
|
|
8
|
+
private readonly idFields;
|
|
9
|
+
mergeObjects(ancestor: JsonValue | undefined, ours: JsonValue, theirs: JsonValue): JsonValue;
|
|
10
|
+
private mergeArrays;
|
|
11
|
+
private hasIdField;
|
|
12
|
+
private createIdMap;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export class JsonMerger {
|
|
2
|
+
idFields = [
|
|
3
|
+
'fullName',
|
|
4
|
+
'name',
|
|
5
|
+
'field',
|
|
6
|
+
'label',
|
|
7
|
+
'id',
|
|
8
|
+
'@_name',
|
|
9
|
+
];
|
|
10
|
+
mergeObjects(ancestor, ours, theirs) {
|
|
11
|
+
// Handle null/undefined cases
|
|
12
|
+
if (ours === null || theirs === null)
|
|
13
|
+
return ours ?? theirs;
|
|
14
|
+
if (typeof ours !== typeof theirs)
|
|
15
|
+
return ours;
|
|
16
|
+
// Handle arrays (special case for Salesforce metadata)
|
|
17
|
+
if (Array.isArray(ours) && Array.isArray(theirs)) {
|
|
18
|
+
return this.mergeArrays(Array.isArray(ancestor) ? ancestor : undefined, ours, theirs);
|
|
19
|
+
}
|
|
20
|
+
// Handle objects
|
|
21
|
+
if (typeof ours === 'object' && typeof theirs === 'object') {
|
|
22
|
+
const result = { ...ours };
|
|
23
|
+
const ancestorObj = (ancestor ?? {});
|
|
24
|
+
const theirsObj = theirs;
|
|
25
|
+
// Process all keys from both objects
|
|
26
|
+
const allKeys = new Set([...Object.keys(ours), ...Object.keys(theirs)]);
|
|
27
|
+
for (const key of allKeys) {
|
|
28
|
+
if (!(key in theirsObj))
|
|
29
|
+
continue; // Keep our version
|
|
30
|
+
if (!(key in result)) {
|
|
31
|
+
result[key] = theirsObj[key]; // Take their version
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
// Recursively merge when both have the key
|
|
35
|
+
result[key] = this.mergeObjects(ancestorObj[key], result[key], theirsObj[key]);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
// For primitive values, use their changes if we didn't modify from ancestor
|
|
40
|
+
if (theirs !== ancestor && ours === ancestor)
|
|
41
|
+
return theirs;
|
|
42
|
+
return ours; // Default to our version
|
|
43
|
+
}
|
|
44
|
+
mergeArrays(ancestor, ours, theirs) {
|
|
45
|
+
// Find the first matching ID field that exists in both arrays
|
|
46
|
+
const idField = this.idFields.find(field => ours.some(item => this.hasIdField(item, field)) &&
|
|
47
|
+
theirs.some(item => this.hasIdField(item, field)));
|
|
48
|
+
if (!idField)
|
|
49
|
+
return ours; // No common identifier, keep our version
|
|
50
|
+
// Create lookup maps
|
|
51
|
+
const ourMap = this.createIdMap(ours, idField);
|
|
52
|
+
const theirMap = this.createIdMap(theirs, idField);
|
|
53
|
+
const ancestorMap = ancestor
|
|
54
|
+
? this.createIdMap(ancestor, idField)
|
|
55
|
+
: new Map();
|
|
56
|
+
const result = [...ours];
|
|
57
|
+
const processed = new Set();
|
|
58
|
+
// Process all items from both arrays
|
|
59
|
+
for (const [id, ourItem] of ourMap) {
|
|
60
|
+
const theirItem = theirMap.get(id);
|
|
61
|
+
if (theirItem) {
|
|
62
|
+
// Item exists in both versions, merge them
|
|
63
|
+
const index = result.findIndex(item => this.hasIdField(item, idField) && item[idField] === id);
|
|
64
|
+
if (index !== -1) {
|
|
65
|
+
result[index] = this.mergeObjects(ancestorMap.get(id), ourItem, theirItem);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
processed.add(id);
|
|
69
|
+
}
|
|
70
|
+
// Add items that only exist in their version
|
|
71
|
+
for (const [id, theirItem] of theirMap) {
|
|
72
|
+
if (!processed.has(id)) {
|
|
73
|
+
result.push(theirItem);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
hasIdField(item, field) {
|
|
79
|
+
return (item !== null &&
|
|
80
|
+
typeof item === 'object' &&
|
|
81
|
+
!Array.isArray(item) &&
|
|
82
|
+
field in item);
|
|
83
|
+
}
|
|
84
|
+
createIdMap(arr, idField) {
|
|
85
|
+
return new Map(arr
|
|
86
|
+
.filter(item => this.hasIdField(item, idField))
|
|
87
|
+
.map(item => [String(item[idField]), item]));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=JsonMerger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"JsonMerger.js","sourceRoot":"","sources":["../../src/merger/JsonMerger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { XMLBuilder, XMLParser } from 'fast-xml-parser';
|
|
2
|
+
import { JsonMerger } from './JsonMerger.js';
|
|
3
|
+
const options = {
|
|
4
|
+
attributeNamePrefix: '@_',
|
|
5
|
+
commentPropName: '#comment',
|
|
6
|
+
format: true,
|
|
7
|
+
ignoreAttributes: false,
|
|
8
|
+
ignoreNameSpace: false,
|
|
9
|
+
indentBy: ' ',
|
|
10
|
+
parseAttributeValue: false,
|
|
11
|
+
parseNodeValue: false,
|
|
12
|
+
parseTagValue: false,
|
|
13
|
+
processEntities: false,
|
|
14
|
+
suppressEmptyNode: false,
|
|
15
|
+
trimValues: true,
|
|
16
|
+
};
|
|
17
|
+
export class XmlMerger {
|
|
18
|
+
async tripartXmlMerge(ancestorContent, ourContent, theirContent) {
|
|
19
|
+
const parser = new XMLParser(options);
|
|
20
|
+
const ancestorObj = parser.parse(ancestorContent);
|
|
21
|
+
const ourObj = parser.parse(ourContent);
|
|
22
|
+
const theirObj = parser.parse(theirContent);
|
|
23
|
+
// Perform deep merge of XML objects
|
|
24
|
+
const jsonMerger = new JsonMerger();
|
|
25
|
+
const mergedObj = jsonMerger.mergeObjects(ancestorObj, ourObj, theirObj);
|
|
26
|
+
// Convert back to XML and format
|
|
27
|
+
const builder = new XMLBuilder(options);
|
|
28
|
+
const mergedXml = builder.build(mergedObj);
|
|
29
|
+
return mergedXml;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=XmlMerger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XmlMerger.js","sourceRoot":"","sources":["../../src/merger/XmlMerger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,MAAM,OAAO,GAAG;IACd,mBAAmB,EAAE,IAAI;IACzB,eAAe,EAAE,UAAU;IAC3B,MAAM,EAAE,IAAI;IACZ,gBAAgB,EAAE,KAAK;IACvB,eAAe,EAAE,KAAK;IACtB,QAAQ,EAAE,MAAM;IAChB,mBAAmB,EAAE,KAAK;IAC1B,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;IACpB,eAAe,EAAE,KAAK;IACtB,iBAAiB,EAAE,KAAK;IACxB,UAAU,EAAE,IAAI;CACjB,CAAA;AAED,MAAM,OAAO,SAAS;IACpB,KAAK,CAAC,eAAe,CACnB,eAAuB,EACvB,UAAkB,EAClB,YAAoB;QAEpB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,CAAA;QAErC,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;QACjD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;QACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAE3C,oCAAoC;QAEpC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAA;QACnC,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;QAExE,iCAAiC;QACjC,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,OAAO,CAAC,CAAA;QACvC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAC1C,OAAO,SAAS,CAAA;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { appendFile, chmod, copyFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { simpleGit } from 'simple-git';
|
|
5
|
+
import { DRIVER_NAME } from '../constant/driverConstant.js';
|
|
6
|
+
const currentDir = fileURLToPath(new URL('.', import.meta.url));
|
|
7
|
+
const libIndexPath = join(currentDir, '../../lib/index.js');
|
|
8
|
+
const binaryPath = 'node_modules/.bin';
|
|
9
|
+
const localBinPath = `${binaryPath}/sf-git-merge-driver`;
|
|
10
|
+
export class InstallService {
|
|
11
|
+
async installMergeDriver() {
|
|
12
|
+
await mkdir(binaryPath, { recursive: true });
|
|
13
|
+
await copyFile(libIndexPath, localBinPath);
|
|
14
|
+
await chmod(localBinPath, 0o755);
|
|
15
|
+
const git = simpleGit();
|
|
16
|
+
await git.addConfig(`merge.${DRIVER_NAME}.name`, 'Salesforce source merge driver');
|
|
17
|
+
await git.addConfig(`merge.${DRIVER_NAME}.driver`, `${localBinPath} %O %A %B %P`);
|
|
18
|
+
await git.addConfig(`merge.${DRIVER_NAME}.recursive`, 'true');
|
|
19
|
+
const content = ['*.xml'].map(pattern => `${pattern} merge=${DRIVER_NAME}`).join('\n') +
|
|
20
|
+
'\n';
|
|
21
|
+
await appendFile('.gitattributes', content, { flag: 'a' });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=installService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installService.js","sourceRoot":"","sources":["../../src/service/installService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAE3D,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAA;AAC3D,MAAM,UAAU,GAAG,mBAAmB,CAAA;AACtC,MAAM,YAAY,GAAG,GAAG,UAAU,sBAAsB,CAAA;AAExD,MAAM,OAAO,cAAc;IAClB,KAAK,CAAC,kBAAkB;QAC7B,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5C,MAAM,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;QAC1C,MAAM,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QAEhC,MAAM,GAAG,GAAG,SAAS,EAAE,CAAA;QACvB,MAAM,GAAG,CAAC,SAAS,CACjB,SAAS,WAAW,OAAO,EAC3B,gCAAgC,CACjC,CAAA;QACD,MAAM,GAAG,CAAC,SAAS,CACjB,SAAS,WAAW,SAAS,EAC7B,GAAG,YAAY,cAAc,CAC9B,CAAA;QACD,MAAM,GAAG,CAAC,SAAS,CAAC,SAAS,WAAW,YAAY,EAAE,MAAM,CAAC,CAAA;QAE7D,MAAM,OAAO,GACX,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,UAAU,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACtE,IAAI,CAAA;QAEN,MAAM,UAAU,CAAC,gBAAgB,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;IAC5D,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { readFile, unlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { simpleGit } from 'simple-git';
|
|
4
|
+
import { DRIVER_NAME } from '../constant/driverConstant.js';
|
|
5
|
+
const MERGE_DRIVER_CONFIG = new RegExp(`.* merge\\s*=\\s*${DRIVER_NAME}$`);
|
|
6
|
+
const localBinPath = join(process.cwd(), 'node_modules/.bin/sf-git-merge-driver');
|
|
7
|
+
export class UninstallService {
|
|
8
|
+
async uninstallMergeDriver() {
|
|
9
|
+
try {
|
|
10
|
+
await unlink(localBinPath);
|
|
11
|
+
// biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>
|
|
12
|
+
}
|
|
13
|
+
catch { }
|
|
14
|
+
const git = simpleGit();
|
|
15
|
+
try {
|
|
16
|
+
await git.raw(['config', '--remove-section', `merge.${DRIVER_NAME}`]);
|
|
17
|
+
// biome-ignore lint/suspicious/noEmptyBlockStatements: <explanation>
|
|
18
|
+
}
|
|
19
|
+
catch { }
|
|
20
|
+
const gitAttributes = await readFile('.gitattributes', {
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
});
|
|
23
|
+
const filteredAttributes = gitAttributes
|
|
24
|
+
.split('\n')
|
|
25
|
+
.filter(line => !MERGE_DRIVER_CONFIG.test(line));
|
|
26
|
+
await writeFile('.gitattributes', filteredAttributes.join('\n'));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=uninstallService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uninstallService.js","sourceRoot":"","sources":["../../src/service/uninstallService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAE3D,MAAM,mBAAmB,GAAG,IAAI,MAAM,CAAC,oBAAoB,WAAW,GAAG,CAAC,CAAA;AAC1E,MAAM,YAAY,GAAG,IAAI,CACvB,OAAO,CAAC,GAAG,EAAE,EACb,uCAAuC,CACxC,CAAA;AAED,MAAM,OAAO,gBAAgB;IACpB,KAAK,CAAC,oBAAoB;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,YAAY,CAAC,CAAA;YAC1B,qEAAqE;QACvE,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,MAAM,GAAG,GAAG,SAAS,EAAE,CAAA;QACvB,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,kBAAkB,EAAE,SAAS,WAAW,EAAE,CAAC,CAAC,CAAA;YACrE,qEAAqE;QACvE,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,gBAAgB,EAAE;YACrD,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAA;QACF,MAAM,kBAAkB,GAAG,aAAa;aACrC,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QAClD,MAAM,SAAS,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAClE,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# summary
|
|
2
|
+
|
|
3
|
+
Installs a local git merge driver for the given org and branch.
|
|
4
|
+
|
|
5
|
+
# description
|
|
6
|
+
|
|
7
|
+
Installs a local git merge driver for the given org and branch, by updating the `.gitattributes` files in the project and creating a new merge driver configuration file in the `.git/config` of the project.
|
|
8
|
+
|
|
9
|
+
# examples
|
|
10
|
+
|
|
11
|
+
- Install the driver for a given project:
|
|
12
|
+
|
|
13
|
+
<%= config.bin %> <%= command.id %>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# summary
|
|
2
|
+
|
|
3
|
+
Uninstalls the local git merge driver for the given org and branch.
|
|
4
|
+
|
|
5
|
+
# description
|
|
6
|
+
|
|
7
|
+
Uninstalls the local git merge driver for the given org and branch, by removing the merge driver content in the `.gitattributes` files in the project and deleting the merge driver configuration file in the `.git/config` of the project.
|
|
8
|
+
|
|
9
|
+
# examples
|
|
10
|
+
|
|
11
|
+
- Uninstall the driver for a given project:
|
|
12
|
+
|
|
13
|
+
<%= config.bin %> <%= command.id %>
|