@salesforce/source-tracking 5.1.18 → 5.2.1
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/lib/index.d.ts +1 -1
- package/lib/index.js +3 -16
- package/lib/shared/conflicts.d.ts +3 -2
- package/lib/shared/conflicts.js +18 -31
- package/lib/shared/functions.d.ts +15 -5
- package/lib/shared/functions.js +38 -10
- package/lib/shared/guards.d.ts +9 -1
- package/lib/shared/guards.js +13 -1
- package/lib/shared/localComponentSetArray.d.ts +6 -2
- package/lib/shared/localComponentSetArray.js +6 -6
- package/lib/shared/localShadowRepo.js +13 -10
- package/lib/shared/metadataKeys.js +1 -0
- package/lib/shared/populateFilePaths.d.ts +6 -1
- package/lib/shared/populateFilePaths.js +24 -26
- package/lib/shared/populateTypesAndNames.d.ts +4 -4
- package/lib/shared/populateTypesAndNames.js +21 -30
- package/lib/shared/remoteChangeIgnoring.d.ts +3 -3
- package/lib/shared/remoteChangeIgnoring.js +16 -22
- package/lib/shared/remoteSourceTrackingService.d.ts +2 -2
- package/lib/shared/remoteSourceTrackingService.js +10 -9
- package/lib/shared/types.d.ts +1 -0
- package/lib/sourceTracking.d.ts +3 -4
- package/lib/sourceTracking.js +79 -111
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
package/lib/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export
|
|
1
|
+
export { SourceTracking, SourceTrackingOptions } from './sourceTracking';
|
|
2
2
|
export { RemoteSyncInput, ChangeOptionType, ChangeOptions, LocalUpdateOptions, ChangeResult, StatusOutputRow, ConflictResponse, SourceConflictError, SourceMemberPollingEvent, } from './shared/types';
|
|
3
3
|
export { getKeyFromObject, deleteCustomLabels } from './shared/functions';
|
package/lib/index.js
CHANGED
|
@@ -5,23 +5,10 @@
|
|
|
5
5
|
* Licensed under the BSD 3-Clause license.
|
|
6
6
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
7
|
*/
|
|
8
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
-
if (k2 === undefined) k2 = k;
|
|
10
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
-
}
|
|
14
|
-
Object.defineProperty(o, k2, desc);
|
|
15
|
-
}) : (function(o, m, k, k2) {
|
|
16
|
-
if (k2 === undefined) k2 = k;
|
|
17
|
-
o[k2] = m[k];
|
|
18
|
-
}));
|
|
19
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
20
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
21
|
-
};
|
|
22
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.deleteCustomLabels = exports.getKeyFromObject = exports.SourceConflictError = void 0;
|
|
24
|
-
|
|
9
|
+
exports.deleteCustomLabels = exports.getKeyFromObject = exports.SourceConflictError = exports.SourceTracking = void 0;
|
|
10
|
+
var sourceTracking_1 = require("./sourceTracking");
|
|
11
|
+
Object.defineProperty(exports, "SourceTracking", { enumerable: true, get: function () { return sourceTracking_1.SourceTracking; } });
|
|
25
12
|
var types_1 = require("./shared/types");
|
|
26
13
|
Object.defineProperty(exports, "SourceConflictError", { enumerable: true, get: function () { return types_1.SourceConflictError; } });
|
|
27
14
|
var functions_1 = require("./shared/functions");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentSet, ForceIgnore } from '@salesforce/source-deploy-retrieve';
|
|
1
|
+
import { ComponentSet, ForceIgnore, RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
2
2
|
import { ConflictResponse, ChangeResult } from './types';
|
|
3
3
|
export declare const throwIfConflicts: (conflicts: ConflictResponse[]) => void;
|
|
4
4
|
/**
|
|
@@ -8,9 +8,10 @@ export declare const throwIfConflicts: (conflicts: ConflictResponse[]) => void;
|
|
|
8
8
|
* @returns ConflictResponse[] de-duped and formatted for json or table display
|
|
9
9
|
*/
|
|
10
10
|
export declare const findConflictsInComponentSet: (cs: ComponentSet, conflicts: ChangeResult[]) => ConflictResponse[];
|
|
11
|
-
export declare const getDedupedConflictsFromChanges: ({ localChanges, remoteChanges, projectPath, forceIgnore, }: {
|
|
11
|
+
export declare const getDedupedConflictsFromChanges: ({ localChanges, remoteChanges, projectPath, forceIgnore, registry, }: {
|
|
12
12
|
localChanges: ChangeResult[];
|
|
13
13
|
remoteChanges: ChangeResult[];
|
|
14
14
|
projectPath: string;
|
|
15
15
|
forceIgnore: ForceIgnore;
|
|
16
|
+
registry: RegistryAccess;
|
|
16
17
|
}) => ChangeResult[];
|
package/lib/shared/conflicts.js
CHANGED
|
@@ -11,6 +11,7 @@ const node_path_1 = require("node:path");
|
|
|
11
11
|
const types_1 = require("./types");
|
|
12
12
|
const functions_1 = require("./functions");
|
|
13
13
|
const populateTypesAndNames_1 = require("./populateTypesAndNames");
|
|
14
|
+
const guards_1 = require("./guards");
|
|
14
15
|
const throwIfConflicts = (conflicts) => {
|
|
15
16
|
if (conflicts.length > 0) {
|
|
16
17
|
throw new types_1.SourceConflictError(`${conflicts.length} conflicts detected`, conflicts);
|
|
@@ -27,13 +28,12 @@ const findConflictsInComponentSet = (cs, conflicts) => {
|
|
|
27
28
|
// map do dedupe by name-type-filename
|
|
28
29
|
const conflictMap = new Map();
|
|
29
30
|
conflicts
|
|
30
|
-
.filter(
|
|
31
|
+
.filter(guards_1.isChangeResultWithNameAndType)
|
|
32
|
+
.filter((cr) => cs.has({ fullName: cr.name, type: cr.type }))
|
|
31
33
|
.forEach((cr) => {
|
|
32
34
|
cr.filenames?.forEach((f) => {
|
|
33
35
|
conflictMap.set(`${cr.name}#${cr.type}#${f}`, {
|
|
34
36
|
state: 'Conflict',
|
|
35
|
-
// the following 2 type assertions are valid because of previous filter statement
|
|
36
|
-
// they can be removed once TS is smarter about filtering
|
|
37
37
|
fullName: cr.name,
|
|
38
38
|
type: cr.type,
|
|
39
39
|
filePath: (0, node_path_1.resolve)(f),
|
|
@@ -44,36 +44,23 @@ const findConflictsInComponentSet = (cs, conflicts) => {
|
|
|
44
44
|
return reformattedConflicts;
|
|
45
45
|
};
|
|
46
46
|
exports.findConflictsInComponentSet = findConflictsInComponentSet;
|
|
47
|
-
const getDedupedConflictsFromChanges = ({ localChanges = [], remoteChanges = [], projectPath, forceIgnore, }) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
remoteChanges.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
change.filenames?.map((filename) => {
|
|
56
|
-
fileNameIndex.set(filename, change);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
const conflicts = new Set();
|
|
60
|
-
(0, populateTypesAndNames_1.populateTypesAndNames)({ elements: localChanges, excludeUnresolvable: true, projectPath, forceIgnore }).map((change) => {
|
|
47
|
+
const getDedupedConflictsFromChanges = ({ localChanges = [], remoteChanges = [], projectPath, forceIgnore, registry, }) => {
|
|
48
|
+
const metadataKeyIndex = new Map(remoteChanges
|
|
49
|
+
.filter(guards_1.isChangeResultWithNameAndType)
|
|
50
|
+
.map((change) => [(0, functions_1.getMetadataKey)(change.name, change.type), change]));
|
|
51
|
+
const fileNameIndex = new Map(remoteChanges.flatMap((change) => (change.filenames ?? []).map((filename) => [filename, change])));
|
|
52
|
+
return (0, populateTypesAndNames_1.populateTypesAndNames)({ excludeUnresolvable: true, projectPath, forceIgnore, registry })(localChanges)
|
|
53
|
+
.filter(guards_1.isChangeResultWithNameAndType)
|
|
54
|
+
.flatMap((change) => {
|
|
61
55
|
const metadataKey = (0, functions_1.getMetadataKey)(change.name, change.type);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (fileNameIndex.has(filename)) {
|
|
70
|
-
conflicts.add({ ...fileNameIndex.get(filename) });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
56
|
+
return metadataKeyIndex.has(metadataKey)
|
|
57
|
+
? // option 1: name and type match
|
|
58
|
+
[metadataKeyIndex.get(metadataKey)]
|
|
59
|
+
: // option 2: some of the filenames match
|
|
60
|
+
(change.filenames ?? [])
|
|
61
|
+
.filter((filename) => fileNameIndex.has(filename))
|
|
62
|
+
.map((filename) => fileNameIndex.get(filename));
|
|
74
63
|
});
|
|
75
|
-
// deeply de-dupe
|
|
76
|
-
return Array.from(conflicts);
|
|
77
64
|
};
|
|
78
65
|
exports.getDedupedConflictsFromChanges = getDedupedConflictsFromChanges;
|
|
79
66
|
//# sourceMappingURL=conflicts.js.map
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { SourceComponent } from '@salesforce/source-deploy-retrieve';
|
|
2
|
-
import { RemoteChangeElement, ChangeResult } from './types';
|
|
1
|
+
import { FileResponseSuccess, ForceIgnore, MetadataComponent, MetadataMember, RegistryAccess, SourceComponent } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import { RemoteChangeElement, ChangeResult, ChangeResultWithNameAndType, RemoteSyncInput } from './types';
|
|
3
3
|
export declare const getMetadataKey: (metadataType: string, metadataName: string) => string;
|
|
4
4
|
export declare const getKeyFromObject: (element: RemoteChangeElement | ChangeResult) => string;
|
|
5
5
|
export declare const supportsPartialDelete: (cmp: SourceComponent) => boolean;
|
|
6
|
-
export declare const
|
|
6
|
+
export declare const excludeLwcLocalOnlyTest: (filePath: string) => boolean;
|
|
7
7
|
/**
|
|
8
8
|
* Verify that a filepath starts exactly with a complete parent path
|
|
9
9
|
* ex: '/foo/bar-extra/baz'.startsWith('foo/bar') would be true, but this function understands that they are not in the same folder
|
|
10
10
|
*/
|
|
11
|
-
export declare const pathIsInFolder: (
|
|
11
|
+
export declare const pathIsInFolder: (folder: string) => (filePath: string) => boolean;
|
|
12
|
+
/** just like pathIsInFolder but with the parameter order reversed for iterating a single file against an array of folders */
|
|
13
|
+
export declare const folderContainsPath: (filePath: string) => (folder: string) => boolean;
|
|
12
14
|
export declare const chunkArray: <T>(arr: T[], size: number) => T[][];
|
|
13
|
-
export declare const ensureRelative: (
|
|
15
|
+
export declare const ensureRelative: (projectPath: string) => (filePath: string) => string;
|
|
14
16
|
export type ParsedCustomLabels = {
|
|
15
17
|
CustomLabels: {
|
|
16
18
|
labels: Array<{
|
|
@@ -26,3 +28,11 @@ export type ParsedCustomLabels = {
|
|
|
26
28
|
* @returns -json equivalent of the custom labels file's contents OR undefined if the file was deleted/not written
|
|
27
29
|
*/
|
|
28
30
|
export declare const deleteCustomLabels: (filename: string, customLabels: SourceComponent[]) => Promise<ParsedCustomLabels | undefined>;
|
|
31
|
+
/** returns true if forceIgnore denies a path OR if there is no forceIgnore provided */
|
|
32
|
+
export declare const forceIgnoreDenies: (forceIgnore?: ForceIgnore) => (filePath: string) => boolean;
|
|
33
|
+
export declare const sourceComponentIsCustomLabel: (input: SourceComponent) => boolean;
|
|
34
|
+
export declare const sourceComponentHasFullNameAndType: (input: SourceComponent) => boolean;
|
|
35
|
+
export declare const getAllFiles: (sc: SourceComponent) => string[];
|
|
36
|
+
export declare const remoteChangeToMetadataMember: (cr: ChangeResult) => MetadataMember;
|
|
37
|
+
export declare const FileResponseSuccessToRemoteSyncInput: (fr: FileResponseSuccess) => RemoteSyncInput;
|
|
38
|
+
export declare const changeResultToMetadataComponent: (registry?: RegistryAccess) => (cr: ChangeResultWithNameAndType) => MetadataComponent;
|
package/lib/shared/functions.js
CHANGED
|
@@ -6,12 +6,14 @@
|
|
|
6
6
|
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.deleteCustomLabels = exports.ensureRelative = exports.chunkArray = exports.pathIsInFolder = exports.
|
|
9
|
+
exports.changeResultToMetadataComponent = exports.FileResponseSuccessToRemoteSyncInput = exports.remoteChangeToMetadataMember = exports.getAllFiles = exports.sourceComponentHasFullNameAndType = exports.sourceComponentIsCustomLabel = exports.forceIgnoreDenies = exports.deleteCustomLabels = exports.ensureRelative = exports.chunkArray = exports.folderContainsPath = exports.pathIsInFolder = exports.excludeLwcLocalOnlyTest = exports.supportsPartialDelete = exports.getKeyFromObject = exports.getMetadataKey = void 0;
|
|
10
10
|
const node_path_1 = require("node:path");
|
|
11
11
|
const fs = require("node:fs");
|
|
12
12
|
const ts_types_1 = require("@salesforce/ts-types");
|
|
13
|
+
const source_deploy_retrieve_1 = require("@salesforce/source-deploy-retrieve");
|
|
13
14
|
const fast_xml_parser_1 = require("fast-xml-parser");
|
|
14
15
|
const kit_1 = require("@salesforce/kit");
|
|
16
|
+
const remoteChangeIgnoring_1 = require("./remoteChangeIgnoring");
|
|
15
17
|
const getMetadataKey = (metadataType, metadataName) => `${metadataType}__${metadataName}`;
|
|
16
18
|
exports.getMetadataKey = getMetadataKey;
|
|
17
19
|
const getKeyFromObject = (element) => {
|
|
@@ -23,13 +25,13 @@ const getKeyFromObject = (element) => {
|
|
|
23
25
|
exports.getKeyFromObject = getKeyFromObject;
|
|
24
26
|
const supportsPartialDelete = (cmp) => !!cmp.type.supportsPartialDelete;
|
|
25
27
|
exports.supportsPartialDelete = supportsPartialDelete;
|
|
26
|
-
const
|
|
27
|
-
exports.
|
|
28
|
+
const excludeLwcLocalOnlyTest = (filePath) => !(filePath.includes('__utam__') || filePath.includes('__tests__'));
|
|
29
|
+
exports.excludeLwcLocalOnlyTest = excludeLwcLocalOnlyTest;
|
|
28
30
|
/**
|
|
29
31
|
* Verify that a filepath starts exactly with a complete parent path
|
|
30
32
|
* ex: '/foo/bar-extra/baz'.startsWith('foo/bar') would be true, but this function understands that they are not in the same folder
|
|
31
33
|
*/
|
|
32
|
-
const pathIsInFolder = (
|
|
34
|
+
const pathIsInFolder = (folder) => (filePath) => {
|
|
33
35
|
const biggerStringParts = (0, node_path_1.normalize)(filePath).split(node_path_1.sep).filter(nonEmptyStringFilter);
|
|
34
36
|
return (0, node_path_1.normalize)(folder)
|
|
35
37
|
.split(node_path_1.sep)
|
|
@@ -37,11 +39,14 @@ const pathIsInFolder = (filePath, folder) => {
|
|
|
37
39
|
.every((part, index) => part === biggerStringParts[index]);
|
|
38
40
|
};
|
|
39
41
|
exports.pathIsInFolder = pathIsInFolder;
|
|
42
|
+
/** just like pathIsInFolder but with the parameter order reversed for iterating a single file against an array of folders */
|
|
43
|
+
const folderContainsPath = (filePath) => (folder) => (0, exports.pathIsInFolder)(folder)(filePath);
|
|
44
|
+
exports.folderContainsPath = folderContainsPath;
|
|
40
45
|
const nonEmptyStringFilter = (value) => (0, ts_types_1.isString)(value) && value.length > 0;
|
|
41
46
|
// adapted for TS from https://github.com/30-seconds/30-seconds-of-code/blob/master/snippets/chunk.md
|
|
42
47
|
const chunkArray = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(i * size, i * size + size));
|
|
43
48
|
exports.chunkArray = chunkArray;
|
|
44
|
-
const ensureRelative = (
|
|
49
|
+
const ensureRelative = (projectPath) => (filePath) => (0, node_path_1.isAbsolute)(filePath) ? (0, node_path_1.relative)(projectPath, filePath) : filePath;
|
|
45
50
|
exports.ensureRelative = ensureRelative;
|
|
46
51
|
/**
|
|
47
52
|
* A method to help delete custom labels from a file, or the entire file if there are no more labels
|
|
@@ -51,11 +56,9 @@ exports.ensureRelative = ensureRelative;
|
|
|
51
56
|
* @returns -json equivalent of the custom labels file's contents OR undefined if the file was deleted/not written
|
|
52
57
|
*/
|
|
53
58
|
const deleteCustomLabels = async (filename, customLabels) => {
|
|
54
|
-
const customLabelsToDelete = customLabels
|
|
55
|
-
.filter((label) => label.type.id === 'customlabel')
|
|
56
|
-
.map((change) => change.fullName);
|
|
59
|
+
const customLabelsToDelete = new Set(customLabels.filter(exports.sourceComponentIsCustomLabel).map((change) => change.fullName));
|
|
57
60
|
// if we don't have custom labels, we don't need to do anything
|
|
58
|
-
if (!customLabelsToDelete.
|
|
61
|
+
if (!customLabelsToDelete.size) {
|
|
59
62
|
return undefined;
|
|
60
63
|
}
|
|
61
64
|
// for custom labels, we need to remove the individual label from the xml file
|
|
@@ -67,7 +70,7 @@ const deleteCustomLabels = async (filename, customLabels) => {
|
|
|
67
70
|
});
|
|
68
71
|
const cls = parser.parse(fs.readFileSync(filename, 'utf8'));
|
|
69
72
|
// delete the labels from the json based on their fullName's
|
|
70
|
-
cls.CustomLabels.labels = (0, kit_1.ensureArray)(cls.CustomLabels.labels).filter((label) => !customLabelsToDelete.
|
|
73
|
+
cls.CustomLabels.labels = (0, kit_1.ensureArray)(cls.CustomLabels.labels).filter((label) => !customLabelsToDelete.has(label.fullName));
|
|
71
74
|
if (cls.CustomLabels.labels.length === 0) {
|
|
72
75
|
// we've deleted everything, so let's delete the file
|
|
73
76
|
await fs.promises.unlink(filename);
|
|
@@ -88,4 +91,29 @@ const deleteCustomLabels = async (filename, customLabels) => {
|
|
|
88
91
|
}
|
|
89
92
|
};
|
|
90
93
|
exports.deleteCustomLabels = deleteCustomLabels;
|
|
94
|
+
/** returns true if forceIgnore denies a path OR if there is no forceIgnore provided */
|
|
95
|
+
const forceIgnoreDenies = (forceIgnore) => (filePath) => forceIgnore?.denies(filePath) ?? false;
|
|
96
|
+
exports.forceIgnoreDenies = forceIgnoreDenies;
|
|
97
|
+
const sourceComponentIsCustomLabel = (input) => input.type.name === 'CustomLabel';
|
|
98
|
+
exports.sourceComponentIsCustomLabel = sourceComponentIsCustomLabel;
|
|
99
|
+
const sourceComponentHasFullNameAndType = (input) => typeof input.fullName === 'string' && typeof input.type.name === 'string';
|
|
100
|
+
exports.sourceComponentHasFullNameAndType = sourceComponentHasFullNameAndType;
|
|
101
|
+
const getAllFiles = (sc) => [sc.xml, ...sc.walkContent()].filter(ts_types_1.isString);
|
|
102
|
+
exports.getAllFiles = getAllFiles;
|
|
103
|
+
const remoteChangeToMetadataMember = (cr) => {
|
|
104
|
+
const checked = (0, remoteChangeIgnoring_1.ensureNameAndType)(cr);
|
|
105
|
+
return {
|
|
106
|
+
fullName: checked.name,
|
|
107
|
+
type: checked.type,
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
exports.remoteChangeToMetadataMember = remoteChangeToMetadataMember;
|
|
111
|
+
// weird, right? This is for oclif.table which allows types but not interfaces. In this case, they are equivalent
|
|
112
|
+
const FileResponseSuccessToRemoteSyncInput = (fr) => fr;
|
|
113
|
+
exports.FileResponseSuccessToRemoteSyncInput = FileResponseSuccessToRemoteSyncInput;
|
|
114
|
+
const changeResultToMetadataComponent = (registry = new source_deploy_retrieve_1.RegistryAccess()) => (cr) => ({
|
|
115
|
+
fullName: cr.name,
|
|
116
|
+
type: registry.getTypeByName(cr.type),
|
|
117
|
+
});
|
|
118
|
+
exports.changeResultToMetadataComponent = changeResultToMetadataComponent;
|
|
91
119
|
//# sourceMappingURL=functions.js.map
|
package/lib/shared/guards.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
-
import { SourceComponent, MetadataMember } from '@salesforce/source-deploy-retrieve';
|
|
1
|
+
import { SourceComponent, MetadataMember, FileResponse, FileResponseFailure, FileResponseSuccess } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import { ChangeResult } from './types';
|
|
3
|
+
import { ChangeResultWithNameAndType } from './types';
|
|
2
4
|
export declare const sourceComponentGuard: (input: SourceComponent | undefined) => input is SourceComponent;
|
|
3
5
|
export declare const metadataMemberGuard: (input: MetadataMember | undefined | Partial<MetadataMember>) => input is MetadataMember;
|
|
6
|
+
export declare const isSdrFailure: (fileResponse: FileResponse) => fileResponse is FileResponseFailure;
|
|
7
|
+
export declare const isSdrSuccess: (fileResponse: FileResponse) => fileResponse is FileResponseSuccess;
|
|
8
|
+
export declare const FileResponseIsDeleted: (fileResponse: FileResponse) => boolean;
|
|
9
|
+
export declare const FileResponseIsNotDeleted: (fileResponse: FileResponse) => boolean;
|
|
10
|
+
export declare const FileResponseHasPath: (fileResponse: FileResponseSuccess) => fileResponse is FileResponseSuccess & Required<Pick<FileResponseSuccess, "filePath">>;
|
|
11
|
+
export declare const isChangeResultWithNameAndType: (cr?: ChangeResult) => cr is ChangeResultWithNameAndType;
|
package/lib/shared/guards.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.metadataMemberGuard = exports.sourceComponentGuard = void 0;
|
|
3
|
+
exports.isChangeResultWithNameAndType = exports.FileResponseHasPath = exports.FileResponseIsNotDeleted = exports.FileResponseIsDeleted = exports.isSdrSuccess = exports.isSdrFailure = exports.metadataMemberGuard = exports.sourceComponentGuard = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Copyright (c) 2020, salesforce.com, inc.
|
|
6
6
|
* All rights reserved.
|
|
@@ -12,4 +12,16 @@ const sourceComponentGuard = (input) => input instanceof source_deploy_retrieve_
|
|
|
12
12
|
exports.sourceComponentGuard = sourceComponentGuard;
|
|
13
13
|
const metadataMemberGuard = (input) => input !== undefined && typeof input.fullName === 'string' && typeof input.type === 'string';
|
|
14
14
|
exports.metadataMemberGuard = metadataMemberGuard;
|
|
15
|
+
const isSdrFailure = (fileResponse) => fileResponse.state === source_deploy_retrieve_1.ComponentStatus.Failed;
|
|
16
|
+
exports.isSdrFailure = isSdrFailure;
|
|
17
|
+
const isSdrSuccess = (fileResponse) => fileResponse.state !== source_deploy_retrieve_1.ComponentStatus.Failed;
|
|
18
|
+
exports.isSdrSuccess = isSdrSuccess;
|
|
19
|
+
const FileResponseIsDeleted = (fileResponse) => fileResponse.state === source_deploy_retrieve_1.ComponentStatus.Deleted;
|
|
20
|
+
exports.FileResponseIsDeleted = FileResponseIsDeleted;
|
|
21
|
+
const FileResponseIsNotDeleted = (fileResponse) => fileResponse.state !== source_deploy_retrieve_1.ComponentStatus.Deleted;
|
|
22
|
+
exports.FileResponseIsNotDeleted = FileResponseIsNotDeleted;
|
|
23
|
+
const FileResponseHasPath = (fileResponse) => fileResponse.filePath !== undefined;
|
|
24
|
+
exports.FileResponseHasPath = FileResponseHasPath;
|
|
25
|
+
const isChangeResultWithNameAndType = (cr) => typeof cr === 'object' && typeof cr.name === 'string' && typeof cr.type === 'string';
|
|
26
|
+
exports.isChangeResultWithNameAndType = isChangeResultWithNameAndType;
|
|
15
27
|
//# sourceMappingURL=guards.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NamedPackageDir } from '@salesforce/core';
|
|
2
|
-
import { ComponentSet } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import { ComponentSet, RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
3
3
|
interface GroupedFileInput {
|
|
4
4
|
packageDirs: NamedPackageDir[];
|
|
5
5
|
nonDeletes: string[];
|
|
@@ -11,5 +11,9 @@ interface GroupedFile {
|
|
|
11
11
|
deletes: string[];
|
|
12
12
|
}
|
|
13
13
|
export declare const getGroupedFiles: (input: GroupedFileInput, byPackageDir?: boolean) => GroupedFile[];
|
|
14
|
-
export declare const getComponentSets: (groupings
|
|
14
|
+
export declare const getComponentSets: ({ groupings, sourceApiVersion, registry, }: {
|
|
15
|
+
groupings: GroupedFile[];
|
|
16
|
+
sourceApiVersion?: string | undefined;
|
|
17
|
+
registry: RegistryAccess;
|
|
18
|
+
}) => ComponentSet[];
|
|
15
19
|
export {};
|
|
@@ -17,8 +17,8 @@ const getGroupedFiles = (input, byPackageDir = false) => (byPackageDir ? getSequ
|
|
|
17
17
|
exports.getGroupedFiles = getGroupedFiles;
|
|
18
18
|
const getSequential = ({ packageDirs, nonDeletes, deletes }) => packageDirs.map((pkgDir) => ({
|
|
19
19
|
path: pkgDir.name,
|
|
20
|
-
nonDeletes: nonDeletes.filter((
|
|
21
|
-
deletes: deletes.filter((
|
|
20
|
+
nonDeletes: nonDeletes.filter((0, functions_1.pathIsInFolder)(pkgDir.name)),
|
|
21
|
+
deletes: deletes.filter((0, functions_1.pathIsInFolder)(pkgDir.name)),
|
|
22
22
|
}));
|
|
23
23
|
const getNonSequential = ({ packageDirs, nonDeletes: nonDeletes, deletes: deletes, }) => [
|
|
24
24
|
{
|
|
@@ -27,20 +27,20 @@ const getNonSequential = ({ packageDirs, nonDeletes: nonDeletes, deletes: delete
|
|
|
27
27
|
path: packageDirs.map((dir) => dir.name).join(';'),
|
|
28
28
|
},
|
|
29
29
|
];
|
|
30
|
-
const getComponentSets = (groupings, sourceApiVersion) => {
|
|
30
|
+
const getComponentSets = ({ groupings, sourceApiVersion, registry = new source_deploy_retrieve_1.RegistryAccess(), }) => {
|
|
31
31
|
const logger = core_1.Logger.childFromRoot('localComponentSetArray');
|
|
32
32
|
// optimistic resolution...some files may not be possible to resolve
|
|
33
|
-
const resolverForNonDeletes = new source_deploy_retrieve_1.MetadataResolver();
|
|
33
|
+
const resolverForNonDeletes = new source_deploy_retrieve_1.MetadataResolver(registry);
|
|
34
34
|
return groupings
|
|
35
35
|
.map((grouping) => {
|
|
36
36
|
logger.debug(`building componentSet for ${grouping.path} (deletes: ${grouping.deletes.length} nonDeletes: ${grouping.nonDeletes.length})`);
|
|
37
|
-
const componentSet = new source_deploy_retrieve_1.ComponentSet();
|
|
37
|
+
const componentSet = new source_deploy_retrieve_1.ComponentSet(undefined, registry);
|
|
38
38
|
if (sourceApiVersion) {
|
|
39
39
|
componentSet.sourceApiVersion = sourceApiVersion;
|
|
40
40
|
}
|
|
41
41
|
// we need virtual components for the deletes.
|
|
42
42
|
// TODO: could we use the same for the non-deletes?
|
|
43
|
-
const resolverForDeletes = new source_deploy_retrieve_1.MetadataResolver(
|
|
43
|
+
const resolverForDeletes = new source_deploy_retrieve_1.MetadataResolver(registry, source_deploy_retrieve_1.VirtualTreeContainer.fromFilePaths(grouping.deletes));
|
|
44
44
|
grouping.deletes
|
|
45
45
|
.flatMap((filename) => resolverForDeletes.getComponentsFromPath(filename))
|
|
46
46
|
.filter(guards_1.sourceComponentGuard)
|
|
@@ -38,7 +38,7 @@ class ShadowRepo {
|
|
|
38
38
|
this.projectPath = options.projectPath;
|
|
39
39
|
this.packageDirs = options.packageDirs;
|
|
40
40
|
this.isWindows = os.type() === 'Windows_NT';
|
|
41
|
-
this.maxFileAdd = kit_1.env.getNumber('SF_SOURCE_TRACKING_BATCH_SIZE', kit_1.env.getNumber('SFDX_SOURCE_TRACKING_BATCH_SIZE', this.isWindows ? 8000 :
|
|
41
|
+
this.maxFileAdd = kit_1.env.getNumber('SF_SOURCE_TRACKING_BATCH_SIZE', kit_1.env.getNumber('SFDX_SOURCE_TRACKING_BATCH_SIZE', this.isWindows ? 8000 : 15_000));
|
|
42
42
|
}
|
|
43
43
|
// think of singleton behavior but unique to the projectPath
|
|
44
44
|
static async getInstance(options) {
|
|
@@ -100,26 +100,24 @@ class ShadowRepo {
|
|
|
100
100
|
// iso-git uses relative, posix paths
|
|
101
101
|
// but packageDirs has already resolved / normalized them
|
|
102
102
|
// so we need to make them project-relative again and convert if windows
|
|
103
|
-
const
|
|
104
|
-
.map((dir) => path.relative(this.projectPath, dir.fullPath))
|
|
105
|
-
.map((p) => (this.isWindows ? p.split(path.sep).join(path.posix.sep) : p));
|
|
103
|
+
const pkgDirs = this.packageDirs.map(packageDirToRelativePosixPath(this.isWindows)(this.projectPath));
|
|
106
104
|
try {
|
|
107
105
|
// status hasn't been initialized yet
|
|
108
106
|
this.status = await git.statusMatrix({
|
|
109
107
|
fs,
|
|
110
108
|
dir: this.projectPath,
|
|
111
109
|
gitdir: this.gitDir,
|
|
112
|
-
filepaths,
|
|
110
|
+
filepaths: pkgDirs,
|
|
113
111
|
ignored: true,
|
|
114
112
|
filter: (f) =>
|
|
115
113
|
// no hidden files
|
|
116
114
|
!f.includes(`${path.sep}.`) &&
|
|
117
115
|
// no lwc tests
|
|
118
|
-
|
|
116
|
+
(0, functions_1.excludeLwcLocalOnlyTest)(f) &&
|
|
119
117
|
// no gitignore files
|
|
120
118
|
!f.endsWith('.gitignore') &&
|
|
121
119
|
// isogit uses `startsWith` for filepaths so it's possible to get a false positive
|
|
122
|
-
|
|
120
|
+
pkgDirs.some((0, functions_1.folderContainsPath)(f)),
|
|
123
121
|
});
|
|
124
122
|
}
|
|
125
123
|
catch (e) {
|
|
@@ -198,10 +196,10 @@ class ShadowRepo {
|
|
|
198
196
|
deletedFiles: deletedFiles.length,
|
|
199
197
|
});
|
|
200
198
|
// these are stored in posix/style/path format. We have to convert inbound stuff from windows
|
|
201
|
-
if (
|
|
199
|
+
if (this.isWindows) {
|
|
202
200
|
this.logger.trace('start: transforming windows paths to posix');
|
|
203
|
-
deployedFiles = deployedFiles.map(
|
|
204
|
-
deletedFiles = deletedFiles.map(
|
|
201
|
+
deployedFiles = deployedFiles.map(normalize).map(ensurePosix);
|
|
202
|
+
deletedFiles = deletedFiles.map(normalize).map(ensurePosix);
|
|
205
203
|
this.logger.trace('done: transforming windows paths to posix');
|
|
206
204
|
}
|
|
207
205
|
if (deployedFiles.length) {
|
|
@@ -266,4 +264,9 @@ class ShadowRepo {
|
|
|
266
264
|
}
|
|
267
265
|
exports.ShadowRepo = ShadowRepo;
|
|
268
266
|
ShadowRepo.instanceMap = new Map();
|
|
267
|
+
const packageDirToRelativePosixPath = (isWindows) => (projectPath) => (packageDir) => isWindows
|
|
268
|
+
? ensurePosix(path.relative(projectPath, packageDir.fullPath))
|
|
269
|
+
: path.relative(projectPath, packageDir.fullPath);
|
|
270
|
+
const normalize = (filepath) => path.normalize(filepath);
|
|
271
|
+
const ensurePosix = (filepath) => filepath.split(path.sep).join(path.posix.sep);
|
|
269
272
|
//# sourceMappingURL=localShadowRepo.js.map
|
|
@@ -20,6 +20,7 @@ const registry = new source_deploy_retrieve_1.RegistryAccess();
|
|
|
20
20
|
// only compute once
|
|
21
21
|
const aliasTypes = registry
|
|
22
22
|
.getAliasTypes()
|
|
23
|
+
// allow assertion because aliasTypes are defined as having that property
|
|
23
24
|
.map((aliasType) => [aliasType.name, registry.getTypeByName(aliasType.aliasFor).name]);
|
|
24
25
|
const reverseAliasTypes = new Map(aliasTypes.map(([alias, type]) => [type, alias]));
|
|
25
26
|
// handle all "weird" type/name translation between SourceMember and SDR FileResponse
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
1
2
|
import { ChangeResult } from './types';
|
|
2
3
|
/**
|
|
3
4
|
* Will build a component set, crawling your local directory, to get paths for remote changes
|
|
@@ -6,4 +7,8 @@ import { ChangeResult } from './types';
|
|
|
6
7
|
* @param packageDirPaths Array of paths from PackageDirectories
|
|
7
8
|
* @returns
|
|
8
9
|
*/
|
|
9
|
-
export declare const populateFilePaths: (elements
|
|
10
|
+
export declare const populateFilePaths: ({ elements, packageDirPaths, registry, }: {
|
|
11
|
+
elements: ChangeResult[];
|
|
12
|
+
packageDirPaths: string[];
|
|
13
|
+
registry: RegistryAccess;
|
|
14
|
+
}) => ChangeResult[];
|
|
@@ -19,7 +19,7 @@ const functions_1 = require("./functions");
|
|
|
19
19
|
* @param packageDirPaths Array of paths from PackageDirectories
|
|
20
20
|
* @returns
|
|
21
21
|
*/
|
|
22
|
-
const populateFilePaths = (elements, packageDirPaths) => {
|
|
22
|
+
const populateFilePaths = ({ elements, packageDirPaths, registry, }) => {
|
|
23
23
|
if (elements.length === 0) {
|
|
24
24
|
return [];
|
|
25
25
|
}
|
|
@@ -28,22 +28,17 @@ const populateFilePaths = (elements, packageDirPaths) => {
|
|
|
28
28
|
// component set generated from an array of MetadataMember from all the remote changes
|
|
29
29
|
// but exclude the ones that aren't in the registry
|
|
30
30
|
const remoteChangesAsMetadataMember = elements
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
type: element.type,
|
|
35
|
-
fullName: element.name,
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
.filter(guards_1.metadataMemberGuard);
|
|
40
|
-
const remoteChangesAsComponentSet = new source_deploy_retrieve_1.ComponentSet(remoteChangesAsMetadataMember);
|
|
31
|
+
.filter(guards_1.isChangeResultWithNameAndType)
|
|
32
|
+
.map(functions_1.remoteChangeToMetadataMember);
|
|
33
|
+
const remoteChangesAsComponentSet = new source_deploy_retrieve_1.ComponentSet(remoteChangesAsMetadataMember, registry);
|
|
41
34
|
logger.debug(` the generated component set has ${remoteChangesAsComponentSet.size.toString()} items`);
|
|
42
35
|
if (remoteChangesAsComponentSet.size < elements.length) {
|
|
43
36
|
// there *could* be something missing
|
|
44
37
|
// some types (ex: LWC) show up as multiple files in the remote changes, but only one in the component set
|
|
45
38
|
// iterate the elements to see which ones didn't make it into the component set
|
|
46
|
-
const missingComponents = elements
|
|
39
|
+
const missingComponents = elements
|
|
40
|
+
.filter(guards_1.isChangeResultWithNameAndType)
|
|
41
|
+
.filter((element) => !remoteChangesAsComponentSet.has({ type: element.type, fullName: element.name }));
|
|
47
42
|
// Throw if anything was actually missing
|
|
48
43
|
if (missingComponents.length > 0) {
|
|
49
44
|
throw new Error(`unable to generate complete component set for ${elements
|
|
@@ -54,25 +49,28 @@ const populateFilePaths = (elements, packageDirPaths) => {
|
|
|
54
49
|
const matchingLocalSourceComponentsSet = source_deploy_retrieve_1.ComponentSet.fromSource({
|
|
55
50
|
fsPaths: packageDirPaths,
|
|
56
51
|
include: remoteChangesAsComponentSet,
|
|
52
|
+
registry,
|
|
57
53
|
});
|
|
58
54
|
logger.debug(` local source-backed component set has ${matchingLocalSourceComponentsSet.size.toString()} items from remote`);
|
|
59
55
|
// make it simpler to find things later
|
|
60
56
|
const elementMap = new Map(elements.map((e) => [(0, functions_1.getKeyFromObject)(e), e]));
|
|
61
57
|
// iterates the local components and sets their filenames
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
matchingLocalSourceComponentsSet
|
|
59
|
+
.getSourceComponents()
|
|
60
|
+
.toArray()
|
|
61
|
+
.filter(functions_1.sourceComponentHasFullNameAndType)
|
|
62
|
+
.map((matchingComponent) => {
|
|
63
|
+
logger.debug(`${matchingComponent.fullName}|${matchingComponent.type.name} matches ${matchingComponent.xml} and maybe ${matchingComponent.walkContent().toString()}`);
|
|
64
|
+
// Decode the key since local components can have encoded fullNames, but results from querying
|
|
65
|
+
// SourceMembers have fullNames that are not encoded. See: https://github.com/forcedotcom/cli/issues/1683
|
|
66
|
+
const key = decodeURIComponent((0, functions_1.getMetadataKey)(matchingComponent.type.name, matchingComponent.fullName));
|
|
67
|
+
elementMap.set(key, {
|
|
68
|
+
...elementMap.get(key),
|
|
69
|
+
modified: true,
|
|
70
|
+
origin: 'remote',
|
|
71
|
+
filenames: (0, functions_1.getAllFiles)(matchingComponent),
|
|
72
|
+
});
|
|
73
|
+
});
|
|
76
74
|
return Array.from(elementMap.values());
|
|
77
75
|
};
|
|
78
76
|
exports.populateFilePaths = populateFilePaths;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ForceIgnore } from '@salesforce/source-deploy-retrieve';
|
|
1
|
+
import { ForceIgnore, RegistryAccess } from '@salesforce/source-deploy-retrieve';
|
|
2
2
|
import { ChangeResult } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* uses SDR to translate remote metadata records into local file paths (which only typically have the filename).
|
|
@@ -9,10 +9,10 @@ import { ChangeResult } from './types';
|
|
|
9
9
|
* @input excludeUnresolvable: boolean Filter out components where you can't get the name and type (that is, it's probably not a valid source component)
|
|
10
10
|
* @input resolveDeleted: constructs a virtualTree instead of the actual filesystem--useful when the files no longer exist
|
|
11
11
|
*/
|
|
12
|
-
export declare const populateTypesAndNames: ({
|
|
13
|
-
elements: ChangeResult[];
|
|
12
|
+
export declare const populateTypesAndNames: ({ projectPath, forceIgnore, excludeUnresolvable, resolveDeleted, registry, }: {
|
|
14
13
|
projectPath: string;
|
|
15
14
|
forceIgnore?: ForceIgnore | undefined;
|
|
16
15
|
excludeUnresolvable?: boolean | undefined;
|
|
17
16
|
resolveDeleted?: boolean | undefined;
|
|
18
|
-
|
|
17
|
+
registry: RegistryAccess;
|
|
18
|
+
}) => (elements: ChangeResult[]) => ChangeResult[];
|