apn-app-manager 1.1.0 → 1.2.0-beta.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/README.md +2 -0
- package/package.json +1 -1
- package/src/actions/cloneAction.js +83 -47
- package/src/cons.js +3 -2
- package/src/handlers/objectExtractHandler.js +42 -10
- package/src/handlers/objectMapsUpdateHandler.js +85 -21
- package/src/handlers/objectModifyHandler.js +23 -9
- package/src/objectProps.js +8 -7
- package/src/util.js +12 -29
- package/APPS.properties +0 -45
- package/APPS.zip +0 -0
- package/AS GSS Full Application.zip +0 -0
- package/AS IO Full Application.zip +0 -0
- package/AS MSG Messaging.zip +0 -0
- package/CT APP Clone Tester.zip +0 -0
- package/NEW - CT APP Clone Tester.zip +0 -0
- package/lib/aim/import-manager_template.properties +0 -50
- package/lib/aim/lib/log4j.properties +0 -17
- package/lib/aim/metrics.properties +0 -10
- package/out/NEW Clone Tester.zip +0 -0
- package/out/namespaces.json +0 -8
- package/out/not-cloned-uuids.json +0 -6
- package/out/objects.json +0 -1090
- package/out/temp/META-INF/MANIFEST.MF +0 -4
- package/out/temp/META-INF/export.log +0 -925
- package/out/temp/META-INF/plugins.txt +0 -4
- package/out/temp/application/_a-0000e88d-6440-8000-9bf2-011c48011c48_855378-new.xml +0 -373
- package/out/temp/connectedSystem/_a-0000e88d-6440-8000-9bf2-011c48011c48_864509-new.xml +0 -63
- package/out/temp/content/1d6e665c-14b4-4bb9-88fb-ae64e1eddbf3-new.xml +0 -75
- package/out/temp/content/6b262b50-0d7a-4dc9-a31b-473fd11f347a-new.xml +0 -100
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_855525-new.xml +0 -181
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863563-new/file.png +0 -0
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863563-new.xml +0 -51
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863564-new.xml +0 -57
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863573-new.xml +0 -50
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863584-new.xml +0 -57
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863603-new/file.properties +0 -1
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863603-new.xml +0 -51
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863609-new.xml +0 -57
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_863616-new.xml +0 -55
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_864578-new.xml +0 -162
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_874621-new.xml +0 -55
- package/out/temp/content/_a-0000e88d-6440-8000-9bf2-011c48011c48_879069.xml +0 -51
- package/out/temp/content/b639666e-eb53-4a1a-b963-c2a21ca400f7-new.xml +0 -89
- package/out/temp/content/c1448a43-e704-42c3-8588-2180b74a138a-new.xml +0 -255
- package/out/temp/content/fcb9b72f-10dd-4744-8870-a44a7fcb4aeb-new.xml +0 -77
- package/out/temp/dataStore/_a-0000e88d-6440-8000-9bf2-011c48011c48_855385-new.xml +0 -57
- package/out/temp/datatype/%7Burn%3Acom%3Aappian%3Atypes%3ANEW%7DNEW_TEST_TABLE.xsd +0 -48
- package/out/temp/datatype/%7Burn%3Acom%3Aappian%3Atypes%3ANEW%7DNEW_TEST_TABLE_REFERENCE.xsd +0 -31
- package/out/temp/group/_e-0000e88d-6440-8000-9b3f-01075c01075c_805-new.xml +0 -29
- package/out/temp/group/_e-0000e88d-6440-8000-9b3f-01075c01075c_807-new.xml +0 -29
- package/out/temp/groupType/_f-0000e88d-6440-8000-9b3f-01075c01075c_1-new.xml +0 -13
- package/out/temp/processModel/0002e8ba-9f2b-8000-1196-7f0000014e7a-new.xml +0 -1964
- package/out/temp/processModelFolder/_g-0000e88d-6441-8000-10c5-7f0000014e7a_197-new.xml +0 -46
- package/out/temp/recordType/00262392-ae09-4941-8b80-d46df28c734f-new.xml +0 -325
- package/out/temp/recordType/0c9e7b5a-c28d-496b-a7c1-8ad7227e513a-new.xml +0 -155
- package/out/temp/recordType/cbbc5029-b0c1-43a2-9430-24fa704c512c-new.xml +0 -223
- package/out/temp/site/15c1e536-fd29-4412-879d-219b02bd1c59-new.xml +0 -47
- package/out/temp/tempoReport/eb755f20-5148-4f8f-92cc-fd69980d6082-new.xml +0 -27
- package/out/temp/webApi/3a013f66-bd81-414a-a72e-bbd03c8befe9-new.xml +0 -62
- package/resources/force_update_.properties +0 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
`apn-app-manager` is a command line tool for managing Appian applications.
|
|
4
4
|
|
|
5
|
+
Test beta version
|
|
6
|
+
|
|
5
7
|
## Why?
|
|
6
8
|
|
|
7
9
|
When app building you may want to do things in bulk that are easiest to do via an application's exported XML files and a re-import. This tool helps to automate some of those tasks.
|
package/package.json
CHANGED
|
@@ -2,6 +2,7 @@ module.exports.main = main;
|
|
|
2
2
|
|
|
3
3
|
// Dependency imports
|
|
4
4
|
const path = require("path");
|
|
5
|
+
const lodash = require("lodash");
|
|
5
6
|
|
|
6
7
|
// Custom imports
|
|
7
8
|
const util = require("../util");
|
|
@@ -14,62 +15,106 @@ const obMapsUpdates = require("../handlers/objectMapsUpdateHandler");
|
|
|
14
15
|
const obModify = require("../handlers/objectModifyHandler");
|
|
15
16
|
|
|
16
17
|
// Entry-point
|
|
17
|
-
function main(
|
|
18
|
+
function main(callback) {
|
|
18
19
|
util.delFile(cons.outDir);
|
|
19
20
|
fileSelect.getAppPackage(function (appZipPath) {
|
|
20
21
|
util.unzipDir(appZipPath, cons.tempDir);
|
|
21
22
|
fileSelect.selectSingleFile("Select import customization properties file", ["properties"], true, function (icfPath) {
|
|
22
|
-
|
|
23
|
-
promptNamespace("What is your new namespace?", function (newNamespace) {
|
|
24
|
-
executeClone(curNamespace, newNamespace, appZipPath, icfPath, callback);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
23
|
+
executeClone(appZipPath, icfPath, callback);
|
|
27
24
|
});
|
|
28
25
|
});
|
|
29
26
|
}
|
|
30
27
|
|
|
31
28
|
// Executes all the steps of the clone
|
|
32
|
-
function executeClone(
|
|
33
|
-
const appName = path.basename(appZipPath, ".zip");
|
|
34
|
-
util.print(`\nCloning '${appName}' to namespace '${newNamespace}'`);
|
|
35
|
-
|
|
29
|
+
function executeClone(appZipPath, icfPath, callback) {
|
|
36
30
|
// Initialize variables based on the new namespace
|
|
37
|
-
const outZipPath = path.resolve(cons.outDir,
|
|
31
|
+
const outZipPath = path.resolve(cons.outDir, path.basename(appZipPath));
|
|
38
32
|
const outIcfPath = icfPath ? path.resolve(cons.outDir, path.basename(icfPath)) : null;
|
|
39
33
|
|
|
40
|
-
// Extract the
|
|
34
|
+
// Extract the metadata including the namespace from each object file
|
|
41
35
|
const objectMaps = {};
|
|
42
36
|
const uuidCollector = { uuids: [] };
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
obMapsUpdates.renameObjectMaps(objectMaps, uuidCollector, curNamespace, newNamespace, obProps.usageTypes.CLONE);
|
|
47
|
-
|
|
48
|
-
// These output files are helpful for debugging
|
|
49
|
-
util.writeJson(path.resolve(cons.outDir, `objects.json`), objectMaps);
|
|
50
|
-
util.writeJson(path.resolve(cons.outDir, `not-cloned-uuids.json`), uuidCollector);
|
|
51
|
-
|
|
52
|
-
// Modify the underlying object XML files
|
|
53
|
-
obModify.modifyObjectFiles(cons.tempDir, objectMaps, obProps.usageTypes.CLONE, []);
|
|
54
|
-
|
|
55
|
-
// Modify the ICF file
|
|
56
|
-
obModify.modifySingleFile(icfPath, outIcfPath, objectMaps, obProps.usageTypes.CLONE, []);
|
|
37
|
+
const namespaceCollector = {};
|
|
38
|
+
util.print(`Collecting all metadata from the objects...`);
|
|
39
|
+
obExtract.buildObjectMaps(objectMaps, uuidCollector, namespaceCollector, cons.tempDir, obProps.usageTypes.CLONE);
|
|
57
40
|
|
|
58
|
-
//
|
|
59
|
-
|
|
41
|
+
// Have the user map each namespace to its proper behavior
|
|
42
|
+
mapNamespaces(namespaceCollector, function onComplete() {
|
|
60
43
|
util.printGap();
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
|
|
44
|
+
// Update the object maps we are cloning based on the application prefix
|
|
45
|
+
util.print(`Cloning the objects files...`);
|
|
46
|
+
obMapsUpdates.renameObjectMaps(objectMaps, uuidCollector, namespaceCollector, obProps.usageTypes.CLONE);
|
|
47
|
+
|
|
48
|
+
// These output files are helpful for debugging
|
|
49
|
+
util.writeJson(path.resolve(cons.outDir, `objects.json`), objectMaps);
|
|
50
|
+
util.writeJson(path.resolve(cons.outDir, `not-cloned-uuids.json`), uuidCollector);
|
|
51
|
+
util.writeJson(path.resolve(cons.outDir, `namespaces.json`), namespaceCollector);
|
|
52
|
+
|
|
53
|
+
// Modify the underlying object XML files & zip the package
|
|
54
|
+
obModify.modifyObjectFiles(cons.tempDir, objectMaps, obProps.usageTypes.CLONE, []);
|
|
55
|
+
util.zipDir(cons.tempDir, outZipPath, false);
|
|
56
|
+
obModify.renameSingleFile(outZipPath, objectMaps, obProps.usageTypes.CLONE, []);
|
|
57
|
+
|
|
58
|
+
// Modify the ICF file
|
|
59
|
+
obModify.modifySingleFile(icfPath, outIcfPath, objectMaps, obProps.usageTypes.CLONE, []);
|
|
60
|
+
|
|
61
|
+
// Print warnings and output
|
|
62
|
+
if (uuidCollector["uuids"].length > 0) {
|
|
63
|
+
util.printGap();
|
|
64
|
+
util.printWarning(
|
|
65
|
+
`WARNING: ${uuidCollector["uuids"].length} uuids were found in your zip but not parsed via cloning (see output file 'not-cloned-uuids.json'). Check the count of missing precedents from your app package in your source environment. If it is ${uuidCollector["uuids"].length} objects, then those are likely just the missing precedents, otherwise please reach out to the authors of this tool, since the XML structure of Appian objects has probably changed and this tool needs to be updated.`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
util.printGap();
|
|
69
|
+
util.print(`Cloning complete. Output can be found in the '/out/' folder (${path.resolve(cons.outDir)}).`);
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
// Execute callback if passed
|
|
72
|
+
util.execCallback(callback, outZipPath);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
// Prompts the user to select a namespace
|
|
77
|
+
function mapNamespaces(namespaceCollector, onComplete) {
|
|
78
|
+
let namespacesToChooseFrom = lodash.filter(obExtract.sortNamespaces(namespaceCollector), function (namespace) {
|
|
79
|
+
return namespaceCollector[namespace]["newNamespace"] == null;
|
|
80
|
+
});
|
|
81
|
+
let isFirstIteration = namespacesToChooseFrom.length == Object.keys(namespaceCollector).length;
|
|
82
|
+
if (namespacesToChooseFrom.length > 0) {
|
|
83
|
+
let message;
|
|
84
|
+
if (isFirstIteration) {
|
|
85
|
+
message = `After analyzing the objects, ${
|
|
86
|
+
Object.keys(namespaceCollector).length
|
|
87
|
+
} potential unique namespaces were found. For each namespace, select what behavior you would like (clone or keep as-is). There may be overlap with sub-prefixes, in which case selecting a shorter namespace that matches ones with more prefixes will result in that behavior applying to all longer matching namespaces. For objects without a namespace, a prefix will automatically be added if they will be cloned. All namespaces with more than 1 prefix are represented with '_' delimiters, although the proper delimiter will automatically be determined by the object type.`;
|
|
88
|
+
} else {
|
|
89
|
+
message = `Select another namespace`;
|
|
90
|
+
}
|
|
91
|
+
prompt.promptList(message, namespacesToChooseFrom, function (answer) {
|
|
92
|
+
let chosenNamespace = answer;
|
|
93
|
+
promptNamespace(
|
|
94
|
+
`Namespace: ${chosenNamespace}. Enter a new namespace to clone these objects. Enter nothing to keep them as-is.`,
|
|
95
|
+
function (answer) {
|
|
96
|
+
Object.keys(namespaceCollector).forEach(namespace => {
|
|
97
|
+
if (namespaceCollector[namespace]["newNamespace"] == null) {
|
|
98
|
+
if (namespace.startsWith(chosenNamespace)) {
|
|
99
|
+
if (namespace == chosenNamespace) {
|
|
100
|
+
namespaceCollector[namespace]["newNamespace"] = answer;
|
|
101
|
+
} else {
|
|
102
|
+
delete namespaceCollector[namespace];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
mapNamespaces(namespaceCollector, onComplete);
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
} else {
|
|
112
|
+
util.print(`All namespaces accounted for. See details below.`);
|
|
113
|
+
obExtract.sortNamespaces(namespaceCollector).forEach(namespace => {
|
|
114
|
+
util.print(` ${namespace} -> ${util.replaceBlank(namespaceCollector[namespace]["newNamespace"], `Will not clone`)}`, true);
|
|
115
|
+
});
|
|
116
|
+
onComplete();
|
|
117
|
+
}
|
|
73
118
|
}
|
|
74
119
|
|
|
75
120
|
// Prompts the user for a namespace
|
|
@@ -79,15 +124,6 @@ function promptNamespace(message, onAnswer) {
|
|
|
79
124
|
});
|
|
80
125
|
}
|
|
81
126
|
|
|
82
|
-
// Returns the module properties
|
|
83
|
-
function getModuleProps() {
|
|
84
|
-
if (util.fileExists(cons.modulePropsPath)) {
|
|
85
|
-
return util.readJson(cons.modulePropsPath);
|
|
86
|
-
} else {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
127
|
// Utility function to differenciate between debug logging and real logging
|
|
92
128
|
function debug(input) {
|
|
93
129
|
console.log(input);
|
package/src/cons.js
CHANGED
|
@@ -33,6 +33,9 @@ module.exports = {
|
|
|
33
33
|
// -- rather than an UUID that is a reference, or connected system third-party id, or just referenced in a code block, or commented out
|
|
34
34
|
uuidRegex: /(?<=>|")[A-Za-z0-9-_]{10,}[0-9][A-Za-z0-9-_]{1,}-[A-Za-z0-9-_]{10,}(?=<|")/g,
|
|
35
35
|
|
|
36
|
+
noNamespace: "Objects with no found namespace",
|
|
37
|
+
namespaceDelimiterRegex: "[:|_| |\\.|-]",
|
|
38
|
+
|
|
36
39
|
xmlEscapedChars: [
|
|
37
40
|
{
|
|
38
41
|
from: `&`,
|
|
@@ -40,7 +43,5 @@ module.exports = {
|
|
|
40
43
|
},
|
|
41
44
|
],
|
|
42
45
|
|
|
43
|
-
namespaceDelimiterRegexString: "([:|_| |\\.|-]?)",
|
|
44
|
-
|
|
45
46
|
appianUrlRegex: /^https:\/\/.*\/suite/g,
|
|
46
47
|
};
|
|
@@ -6,20 +6,21 @@ const path = require("path");
|
|
|
6
6
|
const util = require("../util");
|
|
7
7
|
const cons = require("../cons");
|
|
8
8
|
const obProps = require("../objectProps");
|
|
9
|
+
const { split } = require("lodash");
|
|
9
10
|
|
|
10
11
|
// Exports
|
|
11
12
|
module.exports = {
|
|
12
13
|
// Builds the objectMaps object from the application
|
|
13
|
-
buildObjectMaps: function (objectMaps, uuidCollector, appDir, usageType) {
|
|
14
|
+
buildObjectMaps: function (objectMaps, uuidCollector, namespaceCollector, appDir, usageType) {
|
|
14
15
|
let fileCount = { count: 0 };
|
|
15
16
|
initObjectMaps(objectMaps);
|
|
16
17
|
// Extract the name, uuid, etc. from each object file
|
|
17
18
|
util.handleDirFiles(appDir, ["xml", "xsd"], 2, 2, function (obPath) {
|
|
18
|
-
extractObProps(objectMaps, uuidCollector, fileCount, obPath, usageType);
|
|
19
|
+
extractObProps(objectMaps, uuidCollector, namespaceCollector, fileCount, obPath, usageType);
|
|
19
20
|
});
|
|
20
21
|
// Set the datatype UUIDs from their name & namespace
|
|
21
22
|
updateDatatypeUuids(objectMaps);
|
|
22
|
-
util.print(`${
|
|
23
|
+
util.print(`${retrieveObjectMapCount(objectMaps)} of ${fileCount.count} object files collected`);
|
|
23
24
|
},
|
|
24
25
|
|
|
25
26
|
// Sets the datatype UUIDs from their name & namespace
|
|
@@ -28,7 +29,17 @@ module.exports = {
|
|
|
28
29
|
},
|
|
29
30
|
|
|
30
31
|
// Returns the count of all objects in the objectMap
|
|
31
|
-
|
|
32
|
+
retrieveObjectMapCount: retrieveObjectMapCount,
|
|
33
|
+
|
|
34
|
+
// Sorts the namespaces by their relative lengths
|
|
35
|
+
sortNamespaces: function (namespaceCollector) {
|
|
36
|
+
return lodash.flatten([
|
|
37
|
+
Object.keys(namespaceCollector).indexOf(cons.noNamespace) >= 0 ? cons.noNamespace : [],
|
|
38
|
+
lodash.sortBy(lodash.difference(Object.keys(namespaceCollector), [cons.noNamespace]).sort(), function (namespace) {
|
|
39
|
+
return namespace.split("_").length;
|
|
40
|
+
}),
|
|
41
|
+
]);
|
|
42
|
+
},
|
|
32
43
|
};
|
|
33
44
|
|
|
34
45
|
// ---------------------------------------------------
|
|
@@ -43,7 +54,7 @@ function initObjectMaps(objectMaps) {
|
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
// Extracts the name, uuid, etc. from a single object file
|
|
46
|
-
function extractObProps(objectMaps, uuidCollector, fileCount, obPath, usageType) {
|
|
57
|
+
function extractObProps(objectMaps, uuidCollector, namespaceCollector, fileCount, obPath, usageType) {
|
|
47
58
|
fileCount.count = fileCount.count + 1;
|
|
48
59
|
const obType = util.getFolderName(obPath);
|
|
49
60
|
let isParsed = false;
|
|
@@ -56,20 +67,28 @@ function extractObProps(objectMaps, uuidCollector, fileCount, obPath, usageType)
|
|
|
56
67
|
// Collect all uuids from the file content
|
|
57
68
|
uuidCollector["uuids"] = lodash.union(uuidCollector["uuids"], util.regexMatches(fileContent, cons.uuidRegex));
|
|
58
69
|
|
|
70
|
+
// Collect all metadata from the object
|
|
59
71
|
const builder = {};
|
|
60
72
|
haulType.fields.forEach(haulField => {
|
|
61
73
|
if (lodash.includes(haulField.usage, usageType)) {
|
|
62
74
|
const xpath = util.replaceKeys(haulField.xpath, { "{OBTYPE}": obType });
|
|
63
75
|
let result = util.xpath(xpath, fileContent, haulField.isArray, obProps.xmlNamespaces);
|
|
64
76
|
if (!util.isBlank(haulField.extractRegex) && !util.isBlank(result)) {
|
|
65
|
-
|
|
66
|
-
result = !util.isBlank(matches) ? matches[0] : "";
|
|
77
|
+
result = util.firstMatch(result, haulField.extractRegex, "");
|
|
67
78
|
}
|
|
68
79
|
builder[haulField.fieldName] = result;
|
|
69
80
|
}
|
|
70
81
|
});
|
|
71
|
-
objectMaps[haulType.haulName].push({ current: builder });
|
|
72
82
|
|
|
83
|
+
// Get the namespace of the object
|
|
84
|
+
let objectName = builder[obProps.fieldNames.NAME];
|
|
85
|
+
let objectNamespace = extractObjectNamespace(objectName);
|
|
86
|
+
if (Object.keys(namespaceCollector).indexOf(objectNamespace) == -1) {
|
|
87
|
+
namespaceCollector[objectNamespace] = { newNamespace: null };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Set the object metadata in the objectMaps
|
|
91
|
+
objectMaps[haulType.haulName].push({ current: builder });
|
|
73
92
|
isParsed = true;
|
|
74
93
|
}
|
|
75
94
|
});
|
|
@@ -85,7 +104,8 @@ function updateDatatypeUuids(objectMaps) {
|
|
|
85
104
|
obProps.haulTypes.forEach(haulType => {
|
|
86
105
|
if (lodash.includes(haulType.obs, obProps.obTypes.DATATYPE)) {
|
|
87
106
|
objectMaps[haulType.haulName].forEach(function (objectMap, objectMapIndex) {
|
|
88
|
-
Object.keys(objectMap)
|
|
107
|
+
let keysToProcess = lodash.intersection(["current", "new"], Object.keys(objectMap));
|
|
108
|
+
keysToProcess.forEach(key => {
|
|
89
109
|
const cdtUuid = util.buildCdtUuid(objectMap[key][obProps.fieldNames.CDT_NAMESPACE], objectMap[key][obProps.fieldNames.NAME]);
|
|
90
110
|
objectMaps[haulType.haulName][objectMapIndex][key][obProps.fieldNames.UUID] = cdtUuid;
|
|
91
111
|
objectMaps[haulType.haulName][objectMapIndex][key][obProps.fieldNames.CDT_UUID_ENCODED] = util.encodeCdtUuid(cdtUuid);
|
|
@@ -96,7 +116,7 @@ function updateDatatypeUuids(objectMaps) {
|
|
|
96
116
|
}
|
|
97
117
|
|
|
98
118
|
// Returns the count of all objects in the objectMap
|
|
99
|
-
function
|
|
119
|
+
function retrieveObjectMapCount(objectMaps) {
|
|
100
120
|
let count = 0;
|
|
101
121
|
Object.keys(objectMaps).forEach(key => {
|
|
102
122
|
count = count + objectMaps[key].length;
|
|
@@ -104,6 +124,18 @@ function retriveObjectMapCount(objectMaps) {
|
|
|
104
124
|
return count;
|
|
105
125
|
}
|
|
106
126
|
|
|
127
|
+
// Returns the namespace from an object name
|
|
128
|
+
function extractObjectNamespace(objectName) {
|
|
129
|
+
// See regex here with test cases: https://regexr.com/6trnd
|
|
130
|
+
let namespaceRegex = new RegExp(`^(?:[A-Z0-9]*${cons.namespaceDelimiterRegex}?){0,3}(?=${cons.namespaceDelimiterRegex})`, "g");
|
|
131
|
+
let namespaceMatch = util.firstMatch(objectName, namespaceRegex, null);
|
|
132
|
+
if (namespaceMatch) {
|
|
133
|
+
return namespaceMatch.replace(new RegExp(cons.namespaceDelimiterRegex, "g"), "_");
|
|
134
|
+
} else {
|
|
135
|
+
return cons.noNamespace;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
107
139
|
// Utility function to differenciate between debug logging and real logging
|
|
108
140
|
function debug(input) {
|
|
109
141
|
console.log(input);
|
|
@@ -11,9 +11,9 @@ const { remove } = require("fs-extra");
|
|
|
11
11
|
// Exports
|
|
12
12
|
module.exports = {
|
|
13
13
|
// Goes through all of the objectMaps and creates new name, uuid, etc.
|
|
14
|
-
renameObjectMaps: function (objectMaps, uuidCollector,
|
|
14
|
+
renameObjectMaps: function (objectMaps, uuidCollector, namespaceCollector, usageType) {
|
|
15
15
|
// Update all objectMaps with new names
|
|
16
|
-
renameObjectMaps(objectMaps, uuidCollector,
|
|
16
|
+
renameObjectMaps(objectMaps, uuidCollector, namespaceCollector, usageType);
|
|
17
17
|
},
|
|
18
18
|
};
|
|
19
19
|
|
|
@@ -22,27 +22,41 @@ module.exports = {
|
|
|
22
22
|
// ---------------------------------------------------
|
|
23
23
|
|
|
24
24
|
// Goes through all of the objectMaps and creates new name, uuid, etc.
|
|
25
|
-
function renameObjectMaps(objectMaps, uuidCollector,
|
|
25
|
+
function renameObjectMaps(objectMaps, uuidCollector, namespaceCollector, usageType) {
|
|
26
26
|
obProps.haulTypes.forEach(haulType => {
|
|
27
27
|
objectMaps[haulType.haulName].forEach(function (objectMap, objectMapIndex) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (haulField.
|
|
35
|
-
let
|
|
36
|
-
|
|
37
|
-
newValueArray.push(renameObjectProp(curValueIter, haulField, curNamespace, newNamespace));
|
|
38
|
-
});
|
|
39
|
-
newValue = newValueArray;
|
|
40
|
-
} else {
|
|
41
|
-
newValue = renameObjectProp(curValue, haulField, curNamespace, newNamespace);
|
|
28
|
+
let curNamespaceForObject = findNamespaceForObject(objectMap["current"][obProps.fieldNames.NAME], namespaceCollector);
|
|
29
|
+
let newNamespaceForObject = namespaceCollector[curNamespaceForObject]["newNamespace"];
|
|
30
|
+
if (util.isBlank(newNamespaceForObject)) {
|
|
31
|
+
// Object will not be cloned
|
|
32
|
+
objectMaps[haulType.haulName][objectMapIndex]["new"] = objectMap["current"];
|
|
33
|
+
haulType.fields.forEach(haulField => {
|
|
34
|
+
if (lodash.includes(haulField.usage, usageType)) {
|
|
35
|
+
let curValue = objectMap["current"][haulField.fieldName];
|
|
36
|
+
removeFoundUuids(uuidCollector, haulField, curValue);
|
|
42
37
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
});
|
|
39
|
+
} else {
|
|
40
|
+
// Object will be cloned
|
|
41
|
+
objectMaps[haulType.haulName][objectMapIndex]["new"] = {};
|
|
42
|
+
haulType.fields.forEach(haulField => {
|
|
43
|
+
if (lodash.includes(haulField.usage, usageType)) {
|
|
44
|
+
let newValue;
|
|
45
|
+
let curValue = objectMap["current"][haulField.fieldName];
|
|
46
|
+
removeFoundUuids(uuidCollector, haulField, curValue);
|
|
47
|
+
if (haulField.isArray) {
|
|
48
|
+
let newValueArray = [];
|
|
49
|
+
curValue.forEach(curValueIter => {
|
|
50
|
+
newValueArray.push(renameObjectProp(curValueIter, haulField, curNamespaceForObject, newNamespaceForObject));
|
|
51
|
+
});
|
|
52
|
+
newValue = newValueArray;
|
|
53
|
+
} else {
|
|
54
|
+
newValue = renameObjectProp(curValue, haulField, curNamespaceForObject, newNamespaceForObject);
|
|
55
|
+
}
|
|
56
|
+
objectMaps[haulType.haulName][objectMapIndex]["new"][haulField.fieldName] = newValue;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
46
60
|
});
|
|
47
61
|
});
|
|
48
62
|
// Set UUIDs on the Datatypes
|
|
@@ -54,13 +68,23 @@ function renameObjectProp(curVal, haulField, curNamespace, newNamespace) {
|
|
|
54
68
|
if (util.isBlank(curVal)) {
|
|
55
69
|
return "";
|
|
56
70
|
} else {
|
|
57
|
-
let replacementRegexMap =
|
|
71
|
+
let replacementRegexMap = buildNamespaceReplacementRegex(curNamespace, newNamespace, "gi");
|
|
72
|
+
let nampespaceReplacement;
|
|
58
73
|
switch (haulField.type) {
|
|
74
|
+
// UUIDs - just append the new namespace
|
|
59
75
|
case obProps.propTypes.UUID:
|
|
60
76
|
return `${curVal}-${util.toLower(newNamespace)}`;
|
|
77
|
+
// URL_STUBs - attempt a replacement, but fall back to prefixing if unchanged to ensure they are unique
|
|
61
78
|
case obProps.propTypes.URL_STUB:
|
|
62
79
|
nampespaceReplacement = curVal.replace(replacementRegexMap.from, util.toLower(replacementRegexMap.to));
|
|
63
80
|
return nampespaceReplacement != curVal ? nampespaceReplacement : `${util.toLower(newNamespace)}-${nampespaceReplacement}`;
|
|
81
|
+
// NAMEs - attempt a replacement, but fall back to prefixing if unchanged to ensure they are unique
|
|
82
|
+
case obProps.propTypes.NAME:
|
|
83
|
+
nampespaceReplacement = curVal.replace(replacementRegexMap.from, replacementRegexMap.to);
|
|
84
|
+
return nampespaceReplacement != curVal
|
|
85
|
+
? nampespaceReplacement
|
|
86
|
+
: `${newNamespace}${util.firstMatch(curVal, new RegExp(cons.namespaceDelimiterRegex, "g"), "_")}${nampespaceReplacement}`;
|
|
87
|
+
// TEXTs - just do a replacement, they do not need to be unique
|
|
64
88
|
case obProps.propTypes.TEXT:
|
|
65
89
|
return curVal.replace(replacementRegexMap.from, replacementRegexMap.to);
|
|
66
90
|
}
|
|
@@ -74,6 +98,46 @@ function removeFoundUuids(uuidCollector, haulField, uuids) {
|
|
|
74
98
|
}
|
|
75
99
|
}
|
|
76
100
|
|
|
101
|
+
// Creates the regex replacement for a namespace
|
|
102
|
+
function buildNamespaceReplacementRegex(curNamespace, newNamespace, regexTags) {
|
|
103
|
+
if (curNamespace == cons.noNamespace) {
|
|
104
|
+
return { from: "", to: "" };
|
|
105
|
+
} else {
|
|
106
|
+
// See regex examples here:
|
|
107
|
+
// 1 prefix -> 1 prefix: regexr.com/6t509
|
|
108
|
+
// 1 prefix -> 2 prefix: regexr.com/6t50f
|
|
109
|
+
// 1 prefix -> 3 prefix: regexr.com/6t50i
|
|
110
|
+
// 2 prefix -> 1 prefix: regexr.com/6t50u
|
|
111
|
+
// 2 prefix -> 2 prefix: regexr.com/6t511
|
|
112
|
+
// 2 prefix -> 3 prefix: regexr.com/6t514
|
|
113
|
+
// 3 prefix -> 1 prefix: regexr.com/6t51d
|
|
114
|
+
// 3 prefix -> 2 prefix: regexr.com/6t51j
|
|
115
|
+
// 3 prefix -> 3 prefix: regexr.com/6t51p
|
|
116
|
+
|
|
117
|
+
let namespaceDelimiterRegexStringGrouped = `(${cons.namespaceDelimiterRegex}?)`;
|
|
118
|
+
let findRegex = new RegExp(
|
|
119
|
+
namespaceDelimiterRegexStringGrouped +
|
|
120
|
+
curNamespace.split("_").join(namespaceDelimiterRegexStringGrouped) +
|
|
121
|
+
namespaceDelimiterRegexStringGrouped,
|
|
122
|
+
regexTags
|
|
123
|
+
);
|
|
124
|
+
let curNamespaceLevelCount = curNamespace.split("_").length;
|
|
125
|
+
let replaceStringGroupDelim = curNamespaceLevelCount == 1 ? "$1$2" : "$2";
|
|
126
|
+
let replaceString = "$1" + newNamespace.split("_").join(replaceStringGroupDelim) + "$" + (curNamespaceLevelCount + 1);
|
|
127
|
+
return { from: findRegex, to: replaceString };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Returns the namespace for an object
|
|
132
|
+
function findNamespaceForObject(objectName, namespaceCollector) {
|
|
133
|
+
for (const namespace of obExtract.sortNamespaces(namespaceCollector).reverse()) {
|
|
134
|
+
if (objectName.replace(new RegExp(cons.namespaceDelimiterRegex, "g"), "_").startsWith(namespace)) {
|
|
135
|
+
return namespace;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return cons.noNamespace;
|
|
139
|
+
}
|
|
140
|
+
|
|
77
141
|
// Utility function to differenciate between debug logging and real logging
|
|
78
142
|
function debug(input) {
|
|
79
143
|
console.log(input);
|
|
@@ -9,13 +9,13 @@ const obProps = require("../objectProps");
|
|
|
9
9
|
const obExtract = require("../handlers/objectExtractHandler");
|
|
10
10
|
const { fstat } = require("fs");
|
|
11
11
|
|
|
12
|
+
// Global variables
|
|
13
|
+
const progressToShow = [0.05, 0.25, 0.5, 0.75, 0.95];
|
|
14
|
+
|
|
12
15
|
// Exports
|
|
13
16
|
module.exports = {
|
|
14
17
|
// Actually modifies all of the objects based on the objectMaps
|
|
15
|
-
modifyObjectFiles:
|
|
16
|
-
// Modify the object files
|
|
17
|
-
modifyObjectFiles(appDir, objectMaps, usageType, additionalReplacementMaps);
|
|
18
|
-
},
|
|
18
|
+
modifyObjectFiles: modifyObjectFiles,
|
|
19
19
|
|
|
20
20
|
// Modify a single file
|
|
21
21
|
modifySingleFile: function (filePath, outPath, objectMaps, usageType, additionalReplacementMaps) {
|
|
@@ -28,6 +28,16 @@ module.exports = {
|
|
|
28
28
|
modifyObjectFile(replacementMaps, null, outPath, false);
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
|
+
|
|
32
|
+
// Renames a single file
|
|
33
|
+
renameSingleFile: function (filePath, objectMaps, usageType, additionalReplacementMaps) {
|
|
34
|
+
if (filePath) {
|
|
35
|
+
// Convert the extracted names & uuids to a flat replacement array
|
|
36
|
+
let replacementMaps = buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps);
|
|
37
|
+
// Actually modify the file
|
|
38
|
+
renameObjectFile(replacementMaps, filePath);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
31
41
|
};
|
|
32
42
|
|
|
33
43
|
// ---------------------------------------------------
|
|
@@ -39,7 +49,11 @@ function modifyObjectFiles(appDir, objectMaps, usageType, additionalReplacementM
|
|
|
39
49
|
// Convert the extracted names & uuids to a flat replacement array
|
|
40
50
|
let replacementMaps = buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps);
|
|
41
51
|
// Replace all object files with the new names & uuids
|
|
42
|
-
let fileCount = {
|
|
52
|
+
let fileCount = {
|
|
53
|
+
count: 0,
|
|
54
|
+
total: obExtract.retrieveObjectMapCount(objectMaps),
|
|
55
|
+
nextProgress: progressToShow[0],
|
|
56
|
+
};
|
|
43
57
|
util.handleDirFiles(appDir, ["xml", "xsd", "properties"], 3, 2, function (obPath) {
|
|
44
58
|
modifyObjectFile(replacementMaps, fileCount, obPath, true);
|
|
45
59
|
});
|
|
@@ -76,9 +90,6 @@ function buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps)
|
|
|
76
90
|
});
|
|
77
91
|
});
|
|
78
92
|
replacementMaps = lodash.compact(replacementMaps);
|
|
79
|
-
replacementMaps = lodash.filter(replacementMaps, function (replacementMap) {
|
|
80
|
-
return !(replacementMap.from == replacementMap.to);
|
|
81
|
-
});
|
|
82
93
|
if (!util.isBlank(additionalReplacementMaps)) {
|
|
83
94
|
additionalReplacementMaps.forEach(map => {
|
|
84
95
|
replacementMaps.push(map);
|
|
@@ -111,7 +122,10 @@ function modifyObjectFile(replacementMaps, fileCount, obPath, trackProgress) {
|
|
|
111
122
|
renameObjectFile(replacementMaps, obPath);
|
|
112
123
|
if (trackProgress) {
|
|
113
124
|
fileCount.count = fileCount.count + 1;
|
|
114
|
-
|
|
125
|
+
if (fileCount.count / fileCount.total > fileCount.nextProgress) {
|
|
126
|
+
util.print(`${fileCount.nextProgress * 100}% complete`, true);
|
|
127
|
+
fileCount.nextProgress = progressToShow[progressToShow.indexOf(fileCount.nextProgress) + 1];
|
|
128
|
+
}
|
|
115
129
|
}
|
|
116
130
|
}
|
|
117
131
|
|
package/src/objectProps.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// ---------------------------------------------------
|
|
4
4
|
|
|
5
5
|
const propTypes = {
|
|
6
|
+
NAME: "NAME",
|
|
6
7
|
UUID: "UUID",
|
|
7
8
|
TEXT: "TEXT",
|
|
8
9
|
URL_STUB: "URL_STUB",
|
|
@@ -84,7 +85,7 @@ const haulTypes = [
|
|
|
84
85
|
{
|
|
85
86
|
fieldName: fieldNames.NAME,
|
|
86
87
|
xpath: `xsd:schema/xsd:complexType/@name`,
|
|
87
|
-
type: propTypes.
|
|
88
|
+
type: propTypes.NAME,
|
|
88
89
|
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
89
90
|
},
|
|
90
91
|
{
|
|
@@ -135,7 +136,7 @@ const haulTypes = [
|
|
|
135
136
|
{
|
|
136
137
|
fieldName: fieldNames.NAME,
|
|
137
138
|
xpath: `dataStoreHaul/*[contains(name(), '')]/name/node()`,
|
|
138
|
-
type: propTypes.
|
|
139
|
+
type: propTypes.NAME,
|
|
139
140
|
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
140
141
|
},
|
|
141
142
|
{
|
|
@@ -187,7 +188,7 @@ const haulTypes = [
|
|
|
187
188
|
{
|
|
188
189
|
fieldName: fieldNames.NAME,
|
|
189
190
|
xpath: `processModelHaul/*[local-name()='process_model_port']/*[local-name()='pm']/*[local-name()='meta']/*[local-name()='name']/*[local-name()='string-map']/*[local-name()='pair']/*[local-name()='value']/node()`,
|
|
190
|
-
type: propTypes.
|
|
191
|
+
type: propTypes.NAME,
|
|
191
192
|
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
192
193
|
},
|
|
193
194
|
{
|
|
@@ -239,7 +240,7 @@ const haulTypes = [
|
|
|
239
240
|
{
|
|
240
241
|
fieldName: fieldNames.NAME,
|
|
241
242
|
xpath: `recordTypeHaul/recordType/@name`,
|
|
242
|
-
type: propTypes.
|
|
243
|
+
type: propTypes.NAME,
|
|
243
244
|
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
244
245
|
},
|
|
245
246
|
{
|
|
@@ -346,7 +347,7 @@ const haulTypes = [
|
|
|
346
347
|
{
|
|
347
348
|
fieldName: fieldNames.NAME,
|
|
348
349
|
xpath: `applicationHaul/application/name/node()`,
|
|
349
|
-
type: propTypes.
|
|
350
|
+
type: propTypes.NAME,
|
|
350
351
|
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
351
352
|
},
|
|
352
353
|
{
|
|
@@ -398,7 +399,7 @@ const haulTypes = [
|
|
|
398
399
|
{
|
|
399
400
|
fieldName: fieldNames.NAME,
|
|
400
401
|
xpath: `{OBTYPE}Haul/{OBTYPE}/@name`,
|
|
401
|
-
type: propTypes.
|
|
402
|
+
type: propTypes.NAME,
|
|
402
403
|
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
403
404
|
},
|
|
404
405
|
{
|
|
@@ -443,7 +444,7 @@ const haulTypes = [
|
|
|
443
444
|
{
|
|
444
445
|
fieldName: fieldNames.NAME,
|
|
445
446
|
xpath: `{OBTYPE}Haul/*[contains(name(), '')]/name/node()`,
|
|
446
|
-
type: propTypes.
|
|
447
|
+
type: propTypes.NAME,
|
|
447
448
|
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
448
449
|
},
|
|
449
450
|
{
|