apn-app-manager 1.13.1 → 1.14.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 +3 -3
- package/package.json +1 -1
- package/src/actions/cloneAction.js +81 -24
- package/src/cons.js +12 -0
- package/src/handlers/objectExtractHandler.js +3 -0
- package/src/handlers/objectMapsUpdateHandler.js +32 -7
- package/src/handlers/objectModifyHandler.js +36 -11
- package/src/objectProps.js +9 -1
- package/src/util.js +3 -1
package/README.md
CHANGED
|
@@ -47,11 +47,11 @@ Used to duplicate all objects of an application, which replaces the namespace of
|
|
|
47
47
|
- For example, an application with objects such as `SMP APP Artifacts` and `SMP_APP_displayUser` would have a namespace of `SMP_APP`
|
|
48
48
|
- Note that this tool can only clone objects of one namepsace at a time with regular options.
|
|
49
49
|
- Advanced options:
|
|
50
|
-
1. Select your application or package zip.
|
|
51
|
-
1. If cloning a package, select the zip file(s) that
|
|
50
|
+
1. Select your application or package zip you wish to clone.
|
|
51
|
+
1. If cloning a package which is part of an application which is already cloned in the target environment, select the zip file(s) that your package from the first step contains references to, to ensure all references to objects not in the package are remapped. Use the same namespace configuration you did on the application(s) which were already cloned.
|
|
52
52
|
1. Select your import customization properties file, if you have one.
|
|
53
53
|
1. The tool will search through all object files and attempt to find every unique namespace, allowing you to specify cloning logic for each namepsace.
|
|
54
|
-
1.
|
|
54
|
+
1. Select whether you want database table names (within CDTs and records) to be renamed or not during cloning.
|
|
55
55
|
1. Access your cloned application in the generated `/out/` folder.
|
|
56
56
|
|
|
57
57
|
#### Notes
|
package/package.json
CHANGED
|
@@ -22,6 +22,7 @@ const options = {
|
|
|
22
22
|
const objectMaps = {};
|
|
23
23
|
const uuidCollector = { uuids: [] };
|
|
24
24
|
const namespaceCollector = {};
|
|
25
|
+
const problemWordCollector = { words: [] };
|
|
25
26
|
|
|
26
27
|
let outZipPath;
|
|
27
28
|
let icfPath;
|
|
@@ -37,7 +38,7 @@ function main(callback) {
|
|
|
37
38
|
fileSelect.selectSingleFile("Select application or package zip", ["zip"], false, function (appZipPath) {
|
|
38
39
|
outZipPath = deriveOutPath(appZipPath);
|
|
39
40
|
fileSelect.selectMultipleFiles(
|
|
40
|
-
"Select
|
|
41
|
+
"Select application(s) and package(s) that are referenced by the zip you specified to clone",
|
|
41
42
|
["zip"],
|
|
42
43
|
[appZipPath],
|
|
43
44
|
function (allAppZipPaths) {
|
|
@@ -99,36 +100,43 @@ function executeClone(callback) {
|
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
util.writeJson(path.resolve(cons.outDir, `objects.json`), objectMaps);
|
|
103
|
-
|
|
104
103
|
// Update the object maps we are cloning based on the application prefix
|
|
105
|
-
|
|
106
|
-
obMapsUpdates.renameObjectMaps(objectMaps, uuidCollector, namespaceCollector, options, obProps.usageTypes.CLONE);
|
|
104
|
+
obMapsUpdates.renameObjectMaps(objectMaps, uuidCollector, namespaceCollector, problemWordCollector, options, obProps.usageTypes.CLONE);
|
|
107
105
|
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
// Prompts the user to tell us how to handle problem words
|
|
107
|
+
addressProblemWords(function () {
|
|
108
|
+
// These output files are helpful for debugging
|
|
109
|
+
util.writeJson(path.resolve(cons.outDir, `objects.json`), objectMaps);
|
|
110
|
+
util.writeJson(path.resolve(cons.outDir, `not-cloned-uuids.json`), uuidCollector);
|
|
111
|
+
if (!util.isBlank(namespaceCollector)) {
|
|
112
|
+
util.writeJson(path.resolve(cons.outDir, `namespaces.json`), namespaceCollector);
|
|
113
|
+
}
|
|
114
|
+
if (!util.isBlank(problemWordCollector.words)) {
|
|
115
|
+
util.writeJson(path.resolve(cons.outDir, `problem-terms.json`), problemWordCollector.words);
|
|
116
|
+
}
|
|
111
117
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
118
|
+
// Modify the underlying object XML files & zip the package
|
|
119
|
+
util.print(`Cloning the objects files...`);
|
|
120
|
+
obModify.modifyObjectFiles(cons.tempDir, objectMaps, problemWordCollector.words, obProps.usageTypes.CLONE, []);
|
|
121
|
+
util.zipDir(cons.tempDir, outZipPath, false);
|
|
122
|
+
obModify.renameSingleFile(outZipPath, objectMaps, problemWordCollector.words, obProps.usageTypes.CLONE, []);
|
|
116
123
|
|
|
117
|
-
|
|
118
|
-
|
|
124
|
+
// Modify the ICF file
|
|
125
|
+
obModify.modifySingleFile(icfPath, deriveOutPath(icfPath), objectMaps, problemWordCollector.words, obProps.usageTypes.CLONE, []);
|
|
119
126
|
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
// Print warnings and output
|
|
128
|
+
if (uuidCollector["uuids"].length > 0) {
|
|
129
|
+
util.printGap();
|
|
130
|
+
util.printWarning(
|
|
131
|
+
`${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.`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
122
134
|
util.printGap();
|
|
123
|
-
util.
|
|
124
|
-
`${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.`
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
util.printGap();
|
|
128
|
-
util.print(`Cloning complete. Output can be found in the '/out/' folder (${path.resolve(cons.outDir)}).`);
|
|
135
|
+
util.print(`Cloning complete. Output can be found in the '/out/' folder (${path.resolve(cons.outDir)}).`);
|
|
129
136
|
|
|
130
|
-
|
|
131
|
-
|
|
137
|
+
// Execute callback if passed
|
|
138
|
+
util.execCallback(callback, outZipPath);
|
|
139
|
+
});
|
|
132
140
|
}
|
|
133
141
|
|
|
134
142
|
// Returns the output path from an input path file
|
|
@@ -195,6 +203,55 @@ function mapNamespaces(onComplete) {
|
|
|
195
203
|
obExtract.sortNamespaces(namespaceCollector).forEach(namespace => {
|
|
196
204
|
util.print(` ${namespace} -> ${util.replaceBlank(namespaceCollector[namespace]["newNamespace"], `Will not clone`)}`, true);
|
|
197
205
|
});
|
|
206
|
+
util.printGap();
|
|
207
|
+
onComplete();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Prompts the user to tell us how to handle problem words
|
|
212
|
+
function addressProblemWords(onComplete) {
|
|
213
|
+
let problemWordsToDecide = lodash.filter(problemWordCollector.words, function (wordMap) {
|
|
214
|
+
return util.isBlank(wordMap["decision"]);
|
|
215
|
+
});
|
|
216
|
+
let isFirstIteration = problemWordsToDecide.length == problemWordCollector.words.length;
|
|
217
|
+
if (problemWordsToDecide.length > 0) {
|
|
218
|
+
let message;
|
|
219
|
+
if (isFirstIteration) {
|
|
220
|
+
message = `After analyzing the objects, ${problemWordCollector.words.length} potential problem terms were found. For each term, select what behavior you would like (remap or skip). The cloning tool assumes every reference to a term in the zip should be remapped, therefore it's recommended to skip terms that could also be XML tags or system object terms.`;
|
|
221
|
+
} else {
|
|
222
|
+
message = `Select another term`;
|
|
223
|
+
}
|
|
224
|
+
let problemWordsToDecideMap = {};
|
|
225
|
+
problemWordsToDecide.forEach(wordMap => {
|
|
226
|
+
let formattedMessage = `'${wordMap.current}' -> '${wordMap.new}' (object: '${wordMap.objectName}', property: '${wordMap.haulField}')`;
|
|
227
|
+
problemWordsToDecideMap[formattedMessage] = wordMap;
|
|
228
|
+
});
|
|
229
|
+
prompt.promptList(message, Object.keys(problemWordsToDecideMap), function (answer) {
|
|
230
|
+
let chosenProblemWordMap = problemWordsToDecideMap[answer];
|
|
231
|
+
let options = [];
|
|
232
|
+
Object.keys(cons.problemWordOptions).forEach(option => {
|
|
233
|
+
options.push(cons.problemWordOptions[option]);
|
|
234
|
+
});
|
|
235
|
+
let optionLabels = [];
|
|
236
|
+
options.forEach(option => {
|
|
237
|
+
optionLabels.push(option.label);
|
|
238
|
+
});
|
|
239
|
+
prompt.promptList(`Term: ${answer}. Choose what behavior to do when remapping this term.`, optionLabels, function (answer) {
|
|
240
|
+
let chosenDecision = lodash.filter(options, function (option) {
|
|
241
|
+
return option.label == answer;
|
|
242
|
+
})[0];
|
|
243
|
+
problemWordCollector.words.forEach(function (wordMap, index) {
|
|
244
|
+
if (wordMap.current == chosenProblemWordMap.current && wordMap.new == chosenProblemWordMap.new) {
|
|
245
|
+
problemWordCollector.words[index]["decision"] = chosenDecision.key;
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
addressProblemWords(onComplete);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
} else {
|
|
252
|
+
if (problemWordCollector.words.length > 0) {
|
|
253
|
+
util.print(`All potential problem terms accounted for.`);
|
|
254
|
+
}
|
|
198
255
|
onComplete();
|
|
199
256
|
}
|
|
200
257
|
}
|
package/src/cons.js
CHANGED
|
@@ -44,4 +44,16 @@ module.exports = {
|
|
|
44
44
|
],
|
|
45
45
|
|
|
46
46
|
appianUrlRegex: /^https:\/\/.*\/suite/g,
|
|
47
|
+
|
|
48
|
+
appianSystemObjectUuidRegex: /^SYSTEM_.*$/g,
|
|
49
|
+
|
|
50
|
+
// Problem words are words like "user" or "studio" which can easily map to
|
|
51
|
+
// existing platform terminology/XML tabs like <user></user> or #"SYSTEM_SYSRULES_studio_rule"
|
|
52
|
+
// Testing can be found here: https://regexr.com/827su
|
|
53
|
+
problemWordRegex: /^[a-z0-9]+$/g,
|
|
54
|
+
|
|
55
|
+
problemWordOptions: {
|
|
56
|
+
REMAP_ALL: { key: "REMAP_ALL", label: "Remap all references of this term" },
|
|
57
|
+
REMAP_NONE: { key: "REMAP_NONE", label: "Do not remap this term" },
|
|
58
|
+
},
|
|
47
59
|
};
|
|
@@ -28,6 +28,9 @@ module.exports = {
|
|
|
28
28
|
updateDatatypeUuids(objectMaps);
|
|
29
29
|
},
|
|
30
30
|
|
|
31
|
+
// Returns the count of all objects in the objectMap
|
|
32
|
+
retrieveObjectMapCount: retrieveObjectMapCount,
|
|
33
|
+
|
|
31
34
|
// Sorts the namespaces by their relative lengths
|
|
32
35
|
sortNamespaces: function (namespaceCollector) {
|
|
33
36
|
return lodash.flatten([
|
|
@@ -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, namespaceMap, options, usageType) {
|
|
14
|
+
renameObjectMaps: function (objectMaps, uuidCollector, namespaceMap, problemWordCollector, options, usageType) {
|
|
15
15
|
// Update all objectMaps with new names
|
|
16
|
-
renameObjectMaps(objectMaps, uuidCollector, namespaceMap, options, usageType);
|
|
16
|
+
renameObjectMaps(objectMaps, uuidCollector, namespaceMap, problemWordCollector, options, usageType);
|
|
17
17
|
},
|
|
18
18
|
};
|
|
19
19
|
|
|
@@ -22,13 +22,18 @@ 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, namespaceMap, options, usageType) {
|
|
25
|
+
function renameObjectMaps(objectMaps, uuidCollector, namespaceMap, problemWordCollector, options, usageType) {
|
|
26
26
|
obProps.haulTypes.forEach(haulType => {
|
|
27
27
|
objectMaps[haulType.haulName].forEach(function (objectMap, objectMapIndex) {
|
|
28
28
|
let curNamespaceForObject = findNamespaceForObject(objectMap, namespaceMap, haulType, objectMaps);
|
|
29
29
|
let newNamespaceForObject;
|
|
30
|
-
// Logic to determine if the object will be skipped, either not in the namespaceMap, or the newNamespace is null
|
|
31
|
-
let
|
|
30
|
+
// Logic to determine if the object will be skipped, either not in the namespaceMap, or the newNamespace is null, or it's a system object
|
|
31
|
+
let uuidHaulField = lodash.filter(haulType.fields, function (haulField) {
|
|
32
|
+
return haulField.fieldName == obProps.fieldNames.UUID;
|
|
33
|
+
})[0];
|
|
34
|
+
let objectUuid = objectMap["current"][uuidHaulField.fieldName];
|
|
35
|
+
let objectWillNotBeCloned =
|
|
36
|
+
Object.keys(namespaceMap).indexOf(curNamespaceForObject) < 0 || objectUuid.match(cons.appianSystemObjectUuidRegex);
|
|
32
37
|
if (!objectWillNotBeCloned) {
|
|
33
38
|
newNamespaceForObject = namespaceMap[curNamespaceForObject]["newNamespace"];
|
|
34
39
|
objectWillNotBeCloned = util.isBlank(newNamespaceForObject);
|
|
@@ -45,10 +50,14 @@ function renameObjectMaps(objectMaps, uuidCollector, namespaceMap, options, usag
|
|
|
45
50
|
} else {
|
|
46
51
|
// Object will be cloned
|
|
47
52
|
objectMaps[haulType.haulName][objectMapIndex]["new"] = {};
|
|
53
|
+
let objectName = "";
|
|
48
54
|
haulType.fields.forEach(haulField => {
|
|
49
55
|
if (lodash.includes(haulField.usage, usageType)) {
|
|
50
56
|
let newValue;
|
|
51
57
|
let curValue = objectMap["current"][haulField.fieldName];
|
|
58
|
+
if (haulField.fieldName == obProps.fieldNames.NAME) {
|
|
59
|
+
objectName = curValue;
|
|
60
|
+
}
|
|
52
61
|
removeFoundUuids(uuidCollector, haulField, curValue);
|
|
53
62
|
if (haulField.fieldName == obProps.fieldNames.DB_TABLE && !options.renameDbTables) {
|
|
54
63
|
newValue = curValue;
|
|
@@ -56,14 +65,17 @@ function renameObjectMaps(objectMaps, uuidCollector, namespaceMap, options, usag
|
|
|
56
65
|
if (haulField.isArray) {
|
|
57
66
|
let newValueArray = [];
|
|
58
67
|
curValue.forEach(curValueIter => {
|
|
59
|
-
|
|
68
|
+
let newValueIter = renameObjectProp(curValueIter, haulField, curNamespaceForObject, newNamespaceForObject);
|
|
69
|
+
newValueArray.push(newValueIter);
|
|
70
|
+
checkProblemWord(curValueIter, newValueIter, objectName, haulField, haulType, problemWordCollector);
|
|
60
71
|
});
|
|
61
72
|
newValue = newValueArray;
|
|
62
73
|
} else {
|
|
63
74
|
newValue = renameObjectProp(curValue, haulField, curNamespaceForObject, newNamespaceForObject);
|
|
75
|
+
checkProblemWord(curValue, newValue, objectName, haulField, haulType, problemWordCollector);
|
|
64
76
|
}
|
|
65
|
-
objectMaps[haulType.haulName][objectMapIndex]["new"][haulField.fieldName] = newValue;
|
|
66
77
|
}
|
|
78
|
+
objectMaps[haulType.haulName][objectMapIndex]["new"][haulField.fieldName] = newValue;
|
|
67
79
|
}
|
|
68
80
|
});
|
|
69
81
|
}
|
|
@@ -174,6 +186,19 @@ function findNamespaceForObjectByName(objectName, namespaceMap) {
|
|
|
174
186
|
return cons.noNamespace;
|
|
175
187
|
}
|
|
176
188
|
|
|
189
|
+
// Check if a word might be a problem
|
|
190
|
+
function checkProblemWord(curValue, newValue, objectName, haulField, haulType, problemWordCollector) {
|
|
191
|
+
if (!util.isBlank(newValue) && curValue != newValue && curValue.match(cons.problemWordRegex)) {
|
|
192
|
+
problemWordCollector["words"].push({
|
|
193
|
+
current: curValue,
|
|
194
|
+
new: newValue,
|
|
195
|
+
objectName: objectName,
|
|
196
|
+
haulField: haulField.fieldName,
|
|
197
|
+
haulType: haulType.haulName,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
177
202
|
// Utility function to differenciate between debug logging and real logging
|
|
178
203
|
function debug(input) {
|
|
179
204
|
console.log(input);
|
|
@@ -18,10 +18,10 @@ module.exports = {
|
|
|
18
18
|
modifyObjectFiles: modifyObjectFiles,
|
|
19
19
|
|
|
20
20
|
// Modify a single file
|
|
21
|
-
modifySingleFile: function (filePath, outPath, objectMaps, usageType, additionalReplacementMaps) {
|
|
21
|
+
modifySingleFile: function (filePath, outPath, objectMaps, problemWordsMaps, usageType, additionalReplacementMaps) {
|
|
22
22
|
if (filePath) {
|
|
23
23
|
// Convert the extracted names & uuids to a flat replacement array
|
|
24
|
-
let replacementMaps = buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps);
|
|
24
|
+
let replacementMaps = buildReplacementMaps(objectMaps, problemWordsMaps, usageType, additionalReplacementMaps);
|
|
25
25
|
// Create the file we will update
|
|
26
26
|
util.copyFile(filePath, outPath);
|
|
27
27
|
// Actually modify the file
|
|
@@ -30,10 +30,10 @@ module.exports = {
|
|
|
30
30
|
},
|
|
31
31
|
|
|
32
32
|
// Renames a single file
|
|
33
|
-
renameSingleFile: function (filePath, objectMaps, usageType, additionalReplacementMaps) {
|
|
33
|
+
renameSingleFile: function (filePath, objectMaps, problemWordsMaps, usageType, additionalReplacementMaps) {
|
|
34
34
|
if (filePath) {
|
|
35
35
|
// Convert the extracted names & uuids to a flat replacement array
|
|
36
|
-
let replacementMaps = buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps);
|
|
36
|
+
let replacementMaps = buildReplacementMaps(objectMaps, problemWordsMaps, usageType, additionalReplacementMaps);
|
|
37
37
|
// Actually modify the file
|
|
38
38
|
renameObjectFile(replacementMaps, filePath);
|
|
39
39
|
}
|
|
@@ -45,9 +45,9 @@ module.exports = {
|
|
|
45
45
|
// ---------------------------------------------------
|
|
46
46
|
|
|
47
47
|
// Actually modifies all of the objects based on the objectMaps
|
|
48
|
-
function modifyObjectFiles(appDir, objectMaps, usageType, additionalReplacementMaps) {
|
|
48
|
+
function modifyObjectFiles(appDir, objectMaps, problemWordsMaps, usageType, additionalReplacementMaps) {
|
|
49
49
|
// Convert the extracted names & uuids to a flat replacement array
|
|
50
|
-
let replacementMaps = buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps);
|
|
50
|
+
let replacementMaps = buildReplacementMaps(objectMaps, problemWordsMaps, usageType, additionalReplacementMaps);
|
|
51
51
|
// Determine how many files to change
|
|
52
52
|
let totalCount = 0;
|
|
53
53
|
util.handleDirFiles(appDir, ["xml", "xsd", "properties"], 3, 2, function (obPath) {
|
|
@@ -69,7 +69,7 @@ function modifyObjectFiles(appDir, objectMaps, usageType, additionalReplacementM
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
// Builds the replacementMaps object
|
|
72
|
-
function buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps) {
|
|
72
|
+
function buildReplacementMaps(objectMaps, problemWordsMaps, usageType, additionalReplacementMaps) {
|
|
73
73
|
let replacementMaps = [];
|
|
74
74
|
obProps.haulTypes.forEach(haulType => {
|
|
75
75
|
haulType.fields.forEach(haulField => {
|
|
@@ -81,13 +81,19 @@ function buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps)
|
|
|
81
81
|
buildSingleReplacementMap(
|
|
82
82
|
haulField,
|
|
83
83
|
objectMap["current"][haulField.fieldName][index],
|
|
84
|
-
objectMap["new"][haulField.fieldName][index]
|
|
84
|
+
objectMap["new"][haulField.fieldName][index],
|
|
85
|
+
problemWordsMaps
|
|
85
86
|
)
|
|
86
87
|
);
|
|
87
88
|
});
|
|
88
89
|
} else {
|
|
89
90
|
replacementMaps.push(
|
|
90
|
-
buildSingleReplacementMap(
|
|
91
|
+
buildSingleReplacementMap(
|
|
92
|
+
haulField,
|
|
93
|
+
objectMap["current"][haulField.fieldName],
|
|
94
|
+
objectMap["new"][haulField.fieldName],
|
|
95
|
+
problemWordsMaps
|
|
96
|
+
)
|
|
91
97
|
);
|
|
92
98
|
}
|
|
93
99
|
});
|
|
@@ -104,9 +110,11 @@ function buildReplacementMaps(objectMaps, usageType, additionalReplacementMaps)
|
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
// Returns a single new value for the replacementMap
|
|
107
|
-
function buildSingleReplacementMap(haulField, from, to) {
|
|
113
|
+
function buildSingleReplacementMap(haulField, from, to, problemWordsMaps) {
|
|
108
114
|
if (to == undefined) {
|
|
109
115
|
return null;
|
|
116
|
+
} else if (isReplacementAProblemWordtoSkip(from, to, problemWordsMaps)) {
|
|
117
|
+
return null;
|
|
110
118
|
} else {
|
|
111
119
|
let wordBounded = lodash.includes(obProps.wordBoundedReplacements, haulField.type);
|
|
112
120
|
if (util.isBlank(haulField.replaceFormat)) {
|
|
@@ -121,6 +129,21 @@ function buildSingleReplacementMap(haulField, from, to) {
|
|
|
121
129
|
}
|
|
122
130
|
}
|
|
123
131
|
|
|
132
|
+
// Checks if a replacement is a problem word that should be skipped
|
|
133
|
+
function isReplacementAProblemWordtoSkip(from, to, problemWordsMaps) {
|
|
134
|
+
if (util.isBlank(problemWordsMaps)) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
let matches = lodash.filter(problemWordsMaps, function (map) {
|
|
138
|
+
return from == map["current"] && to == map["new"];
|
|
139
|
+
});
|
|
140
|
+
if (matches.length > 0) {
|
|
141
|
+
return matches[0]["decision"] == cons.problemWordOptions.REMAP_NONE["key"];
|
|
142
|
+
} else {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
124
147
|
// Modifies a single object files
|
|
125
148
|
function modifyObjectFile(replacementMaps, fileCount, obPath, trackProgress) {
|
|
126
149
|
let content = util.readFile(obPath);
|
|
@@ -138,7 +161,9 @@ function modifyObjectFile(replacementMaps, fileCount, obPath, trackProgress) {
|
|
|
138
161
|
|
|
139
162
|
// Renames a single object file
|
|
140
163
|
function renameObjectFile(replacementMaps, obPath) {
|
|
141
|
-
|
|
164
|
+
let relativePath = path.relative(".", obPath).toString();
|
|
165
|
+
let newRelativePath = util.replaceMaps(relativePath, replacementMaps);
|
|
166
|
+
util.renameFile(obPath, path.resolve(newRelativePath));
|
|
142
167
|
}
|
|
143
168
|
|
|
144
169
|
// Utility function to differenciate between debug logging and real logging
|
package/src/objectProps.js
CHANGED
|
@@ -9,7 +9,7 @@ const propTypes = {
|
|
|
9
9
|
URL_STUB: "URL_STUB",
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
const wordBoundedReplacements = [propTypes.URL_STUB];
|
|
12
|
+
const wordBoundedReplacements = [propTypes.NAME, propTypes.URL_STUB];
|
|
13
13
|
|
|
14
14
|
const obTypes = {
|
|
15
15
|
DATATYPE: "datatype",
|
|
@@ -52,6 +52,7 @@ const fieldNames = {
|
|
|
52
52
|
PAGE_UUIDS: "pageUuids",
|
|
53
53
|
APP_PREFIX: "appPrefix",
|
|
54
54
|
APP_ACTION_UUIDS: "appActionUuids",
|
|
55
|
+
RECORD_PLURAL_NAME: "pluralName",
|
|
55
56
|
RECORD_ACTION_UUIDS: "recordActionUuids",
|
|
56
57
|
RECORD_ACTION_REF_IDS: "recordActionRefIds",
|
|
57
58
|
RECORD_FIELD_UUIDS: "fieldUuids",
|
|
@@ -286,6 +287,13 @@ const haulTypes = [
|
|
|
286
287
|
usage: [usageTypes.CLONE, usageTypes.BUILD],
|
|
287
288
|
isArray: true,
|
|
288
289
|
},
|
|
290
|
+
{
|
|
291
|
+
fieldName: fieldNames.RECORD_PLURAL_NAME,
|
|
292
|
+
xpath: `recordTypeHaul/recordType/a:pluralName/node()`,
|
|
293
|
+
type: propTypes.TEXT,
|
|
294
|
+
usage: [usageTypes.CLONE, usageTypes.BUILD, usageTypes.RENAME],
|
|
295
|
+
replaceFormat: "<a:pluralName>{VALUE}</a:pluralName>",
|
|
296
|
+
},
|
|
289
297
|
{
|
|
290
298
|
fieldName: fieldNames.URL_STUB,
|
|
291
299
|
xpath: `recordTypeHaul/recordType/a:urlStub/node()`,
|
package/src/util.js
CHANGED
|
@@ -492,7 +492,9 @@ function replaceMaps(inStr, maps) {
|
|
|
492
492
|
let replaceMaps = [];
|
|
493
493
|
|
|
494
494
|
maps.forEach(map => {
|
|
495
|
-
|
|
495
|
+
if (!isBlank(map) && map.from != map.to) {
|
|
496
|
+
replaceMaps.push({ from: map.from, temp: buildNewUuid(), to: map.to, wordBounded: map.wordBounded });
|
|
497
|
+
}
|
|
496
498
|
});
|
|
497
499
|
|
|
498
500
|
replaceMaps = arrayByFieldLenth(replaceMaps, "from"); // Order the array by longest to shortest
|