@salesforce/plugin-omnistudio-migration-tool 2.0.0-rc.60 → 2.0.0-rc.61
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/commands/omnistudio/migration/assess.d.ts +1 -0
- package/lib/commands/omnistudio/migration/assess.js +27 -0
- package/lib/commands/omnistudio/migration/assess.js.map +1 -1
- package/lib/commands/omnistudio/migration/clean.js +4 -2
- package/lib/commands/omnistudio/migration/clean.js.map +1 -1
- package/lib/commands/omnistudio/migration/migrate.js +11 -0
- package/lib/commands/omnistudio/migration/migrate.js.map +1 -1
- package/lib/javascripts/reportGeneratorUtility.js +181 -0
- package/lib/migration/ApexNamespaceRegistry.d.ts +49 -0
- package/lib/migration/ApexNamespaceRegistry.js +130 -0
- package/lib/migration/ApexNamespaceRegistry.js.map +1 -0
- package/lib/migration/CustomCssRegistry.d.ts +117 -0
- package/lib/migration/CustomCssRegistry.js +234 -0
- package/lib/migration/CustomCssRegistry.js.map +1 -0
- package/lib/migration/base.js +1 -1
- package/lib/migration/base.js.map +1 -1
- package/lib/migration/customLabels.js +14 -3
- package/lib/migration/customLabels.js.map +1 -1
- package/lib/migration/flexcard.d.ts +98 -0
- package/lib/migration/flexcard.js +448 -15
- package/lib/migration/flexcard.js.map +1 -1
- package/lib/migration/interfaces.d.ts +1 -0
- package/lib/migration/interfaces.js.map +1 -1
- package/lib/migration/omniscript.d.ts +42 -1
- package/lib/migration/omniscript.js +249 -6
- package/lib/migration/omniscript.js.map +1 -1
- package/lib/migration/omniscriptInstance.d.ts +90 -0
- package/lib/migration/omniscriptInstance.js +755 -0
- package/lib/migration/omniscriptInstance.js.map +1 -0
- package/lib/styles/reportGenerator.css +25 -0
- package/lib/templates/assessmentReport.template +8 -0
- package/lib/templates/migrationReport.template +8 -0
- package/lib/utils/constants/documentRegistry.d.ts +6 -0
- package/lib/utils/constants/documentRegistry.js +6 -0
- package/lib/utils/constants/documentRegistry.js.map +1 -1
- package/lib/utils/constants/stringContants.d.ts +28 -5
- package/lib/utils/constants/stringContants.js +30 -5
- package/lib/utils/constants/stringContants.js.map +1 -1
- package/lib/utils/customLabels.d.ts +1 -0
- package/lib/utils/customLabels.js +3 -0
- package/lib/utils/customLabels.js.map +1 -1
- package/lib/utils/interfaces.d.ts +19 -0
- package/lib/utils/query/index.d.ts +1 -0
- package/lib/utils/query/index.js +17 -0
- package/lib/utils/query/index.js.map +1 -1
- package/lib/utils/resultsbuilder/FlexcardAssessmentReporter.js +4 -0
- package/lib/utils/resultsbuilder/FlexcardAssessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.d.ts +12 -0
- package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.js +109 -0
- package/lib/utils/resultsbuilder/SaveForLaterAssessmentReporter.js.map +1 -0
- package/lib/utils/resultsbuilder/assessmentReporter.js +18 -2
- package/lib/utils/resultsbuilder/assessmentReporter.js.map +1 -1
- package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.d.ts +11 -1
- package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.js +64 -1
- package/lib/utils/resultsbuilder/helpers/AssessmentReportHelper.js.map +1 -1
- package/lib/utils/resultsbuilder/index.d.ts +4 -0
- package/lib/utils/resultsbuilder/index.js +61 -0
- package/lib/utils/resultsbuilder/index.js.map +1 -1
- package/lib/utils/stringUtils.d.ts +15 -0
- package/lib/utils/stringUtils.js +37 -0
- package/lib/utils/stringUtils.js.map +1 -1
- package/messages/assess.json +23 -2
- package/messages/migrate.json +29 -3
- package/oclif.manifest.json +1 -1
- package/package.json +5 -4
|
@@ -8,6 +8,7 @@ const VlocityCard_1 = __importDefault(require("../mappings/VlocityCard"));
|
|
|
8
8
|
const utils_1 = require("../utils");
|
|
9
9
|
const net_1 = require("../utils/net");
|
|
10
10
|
const base_1 = require("./base");
|
|
11
|
+
const CustomCssRegistry_1 = require("./CustomCssRegistry");
|
|
11
12
|
const interfaces_1 = require("./interfaces");
|
|
12
13
|
const logger_1 = require("../utils/logger");
|
|
13
14
|
const base_2 = require("./base");
|
|
@@ -16,11 +17,14 @@ const storageUtil_1 = require("../utils/storageUtil");
|
|
|
16
17
|
const stringUtils_1 = require("../utils/stringUtils");
|
|
17
18
|
const dataModelService_1 = require("../utils/dataModelService");
|
|
18
19
|
const recordPrioritization_1 = require("../utils/recordPrioritization");
|
|
20
|
+
const ApexNamespaceRegistry_1 = require("./ApexNamespaceRegistry");
|
|
19
21
|
class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
20
22
|
constructor(namespace, connection, logger, messages, ux, allVersions) {
|
|
21
23
|
super(namespace, connection, logger, messages, ux);
|
|
24
|
+
this.apexNamespaceRegistry = ApexNamespaceRegistry_1.ApexNamespaceRegistry.getInstance();
|
|
22
25
|
this.IS_STANDARD_DATA_MODEL = (0, dataModelService_1.isStandardDataModel)();
|
|
23
26
|
this.allVersions = allVersions;
|
|
27
|
+
CustomCssRegistry_1.CustomCssRegistry.getInstance().init(connection, namespace, messages);
|
|
24
28
|
}
|
|
25
29
|
getName() {
|
|
26
30
|
return 'Flexcards';
|
|
@@ -160,6 +164,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
160
164
|
dependenciesOS: [],
|
|
161
165
|
dependenciesLWC: [],
|
|
162
166
|
dependenciesApexRemoteAction: [],
|
|
167
|
+
dependenciesVlocityAction: [],
|
|
163
168
|
infos: [],
|
|
164
169
|
warnings: [],
|
|
165
170
|
errors: [this.messages.getMessage('unexpectedError')],
|
|
@@ -187,6 +192,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
187
192
|
dependenciesFC: [],
|
|
188
193
|
dependenciesLWC: [],
|
|
189
194
|
dependenciesApexRemoteAction: [],
|
|
195
|
+
dependenciesVlocityAction: [],
|
|
190
196
|
infos: [],
|
|
191
197
|
warnings: [],
|
|
192
198
|
errors: [],
|
|
@@ -237,6 +243,17 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
237
243
|
};
|
|
238
244
|
flexCardAssessmentInfo.migrationStatus = assessmentStatus;
|
|
239
245
|
this.updateDependencies(flexCard, flexCardAssessmentInfo);
|
|
246
|
+
// Scan custom CSS (both StaticResource-backed and inline) for managed-package
|
|
247
|
+
// namespace references. The helper updates `migrationStatus` itself via
|
|
248
|
+
// `getUpdatedAssessmentStatus`, so it never downgrades a stricter status.
|
|
249
|
+
await this.collectStylesheetNamespaceDependencies(flexCard, flexCardAssessmentInfo);
|
|
250
|
+
if (flexCardAssessmentInfo.errors.length > 0) {
|
|
251
|
+
flexCardAssessmentInfo.migrationStatus = 'Needs manual intervention';
|
|
252
|
+
}
|
|
253
|
+
else if (flexCardAssessmentInfo.warnings.length > 0 &&
|
|
254
|
+
flexCardAssessmentInfo.migrationStatus === 'Ready for migration') {
|
|
255
|
+
flexCardAssessmentInfo.migrationStatus = 'Warnings';
|
|
256
|
+
}
|
|
240
257
|
// Deduplicate all dependency arrays to ensure no duplicates
|
|
241
258
|
flexCardAssessmentInfo.dependenciesIP = [...new Set(flexCardAssessmentInfo.dependenciesIP)];
|
|
242
259
|
flexCardAssessmentInfo.dependenciesDR = [...new Set(flexCardAssessmentInfo.dependenciesDR)];
|
|
@@ -246,8 +263,77 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
246
263
|
flexCardAssessmentInfo.dependenciesApexRemoteAction = [
|
|
247
264
|
...new Set(flexCardAssessmentInfo.dependenciesApexRemoteAction),
|
|
248
265
|
];
|
|
266
|
+
flexCardAssessmentInfo.dependenciesVlocityAction = [...new Set(flexCardAssessmentInfo.dependenciesVlocityAction)];
|
|
249
267
|
return flexCardAssessmentInfo;
|
|
250
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* Scan a FlexCard for two distinct kinds of namespace-bound custom CSS:
|
|
271
|
+
*
|
|
272
|
+
* 1. **StaticResource-backed stylesheet** — `Definition__c.customStyleSheet`
|
|
273
|
+
* stores the *Name* of a Static Resource. We look it up, fetch its body,
|
|
274
|
+
* and substring-check for the org's managed-package namespace. Same flow
|
|
275
|
+
* and same warning message as the OmniScript implementation; resource
|
|
276
|
+
* scans are cached by name in {@link CustomCssRegistry}, so a stylesheet
|
|
277
|
+
* shared between OmniScripts and FlexCards is only fetched once per run.
|
|
278
|
+
*
|
|
279
|
+
* 2. **Inline CSS** — `Styles__c.customStyles` stores raw CSS text. We
|
|
280
|
+
* substring-check the namespace directly against that string. No
|
|
281
|
+
* SOQL/REST traffic and no caching (the CSS is per-FlexCard and not
|
|
282
|
+
* shared across records).
|
|
283
|
+
*
|
|
284
|
+
* Both checks emit a warning into `flexCardAssessmentInfo.warnings` and bump
|
|
285
|
+
* `migrationStatus` to 'Needs manual intervention' (via
|
|
286
|
+
* `getUpdatedAssessmentStatus`, which never downgrades a stricter status).
|
|
287
|
+
*/
|
|
288
|
+
async collectStylesheetNamespaceDependencies(flexCard, flexCardAssessmentInfo) {
|
|
289
|
+
const registry = CustomCssRegistry_1.CustomCssRegistry.getInstance();
|
|
290
|
+
if (!registry.isEnabled()) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// ---- 1. Definition__c.customStyleSheet (StaticResource name) ----
|
|
294
|
+
const definitionRaw = flexCard[this.getFieldKey('Definition__c')];
|
|
295
|
+
if (definitionRaw) {
|
|
296
|
+
let definition;
|
|
297
|
+
try {
|
|
298
|
+
definition = JSON.parse(definitionRaw);
|
|
299
|
+
}
|
|
300
|
+
catch (ex) {
|
|
301
|
+
logger_1.Logger.error(`Failed to parse Definition__c for stylesheet scan: ${flexCard['Name']}`);
|
|
302
|
+
definition = null;
|
|
303
|
+
}
|
|
304
|
+
const resourceName = ((definition === null || definition === void 0 ? void 0 : definition.customStyleSheet) || '').toString().trim();
|
|
305
|
+
if (resourceName) {
|
|
306
|
+
const verdict = await registry.scanResource(resourceName);
|
|
307
|
+
if (verdict === 'namespaceFound') {
|
|
308
|
+
const message = registry.buildFlexCardNamespaceWarning(resourceName);
|
|
309
|
+
if (message) {
|
|
310
|
+
flexCardAssessmentInfo.warnings.push(message);
|
|
311
|
+
flexCardAssessmentInfo.migrationStatus = (0, stringUtils_1.getUpdatedAssessmentStatus)(flexCardAssessmentInfo.migrationStatus, 'Needs manual intervention');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// ---- 2. Styles__c.customStyles (raw inline CSS) ----
|
|
317
|
+
const stylesRaw = flexCard[this.getFieldKey('Styles__c')];
|
|
318
|
+
if (stylesRaw) {
|
|
319
|
+
let styles;
|
|
320
|
+
try {
|
|
321
|
+
styles = JSON.parse(stylesRaw);
|
|
322
|
+
}
|
|
323
|
+
catch (ex) {
|
|
324
|
+
logger_1.Logger.error(`Failed to parse Styles__c for stylesheet scan: ${flexCard['Name']}`);
|
|
325
|
+
styles = null;
|
|
326
|
+
}
|
|
327
|
+
const inlineCss = styles === null || styles === void 0 ? void 0 : styles.customStyles;
|
|
328
|
+
if (registry.containsNamespaceInText(inlineCss)) {
|
|
329
|
+
const message = registry.buildInlineCssNamespaceWarning();
|
|
330
|
+
if (message) {
|
|
331
|
+
flexCardAssessmentInfo.warnings.push(message);
|
|
332
|
+
flexCardAssessmentInfo.migrationStatus = (0, stringUtils_1.getUpdatedAssessmentStatus)(flexCardAssessmentInfo.migrationStatus, 'Needs manual intervention');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
251
337
|
updateDependencies(flexCard, flexCardAssessmentInfo) {
|
|
252
338
|
var _a, _b, _c, _d;
|
|
253
339
|
const dataSourceConfig = JSON.parse(flexCard[this.getFieldKey('Datasource__c')] || '{}');
|
|
@@ -271,10 +357,19 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
271
357
|
else if (ds.type === stringContants_1.Constants.ApexRemoteComponentName) {
|
|
272
358
|
const remoteClass = (_c = ds.value) === null || _c === void 0 ? void 0 : _c.remoteClass;
|
|
273
359
|
const remoteMethod = (_d = ds.value) === null || _d === void 0 ? void 0 : _d.remoteMethod;
|
|
274
|
-
if (remoteClass &&
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
360
|
+
if (remoteClass && remoteMethod) {
|
|
361
|
+
const status = this.apexNamespaceRegistry.resolveStatus(remoteClass);
|
|
362
|
+
const qualifiedClass = this.apexNamespaceRegistry.getQualifiedClassName(remoteClass);
|
|
363
|
+
const qualifiedEntry = `${qualifiedClass}.${remoteMethod}`;
|
|
364
|
+
if (!flexCardAssessmentInfo.dependenciesApexRemoteAction.includes(qualifiedEntry)) {
|
|
365
|
+
flexCardAssessmentInfo.dependenciesApexRemoteAction.push(qualifiedEntry);
|
|
366
|
+
}
|
|
367
|
+
if (status === ApexNamespaceRegistry_1.ApexResolveStatus.NAMESPACED) {
|
|
368
|
+
flexCardAssessmentInfo.warnings.push(this.messages.getMessage('apexRemoteDatasourceNamespaceWarning', [remoteClass, qualifiedClass]));
|
|
369
|
+
}
|
|
370
|
+
else if (status === ApexNamespaceRegistry_1.ApexResolveStatus.NOT_FOUND) {
|
|
371
|
+
flexCardAssessmentInfo.errors.push(this.messages.getMessage('apexClassNotFound', [remoteClass, flexCardAssessmentInfo.name]));
|
|
372
|
+
}
|
|
278
373
|
}
|
|
279
374
|
}
|
|
280
375
|
}
|
|
@@ -330,6 +425,10 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
330
425
|
continue;
|
|
331
426
|
}
|
|
332
427
|
const stateAction = action.stateAction;
|
|
428
|
+
// Detect Vlocity Action (not supported in standard runtime FlexCards)
|
|
429
|
+
if (stateAction.type === stringContants_1.Constants.VlocityAction) {
|
|
430
|
+
this.addVlocityActionDependency(stateAction, flexCardAssessmentInfo);
|
|
431
|
+
}
|
|
333
432
|
// 1-2. Handle message.value.bundle (DataRaptor) and message.value.ipMethod (Integration Procedure)
|
|
334
433
|
this.processStateActionMessageForDependencies(stateAction, flexCardAssessmentInfo);
|
|
335
434
|
// 3. Handle cardName (FlexCard - Flyout childCard)
|
|
@@ -411,6 +510,15 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
411
510
|
flexCardAssessmentInfo.dependenciesLWC.push(customLwcName);
|
|
412
511
|
}
|
|
413
512
|
}
|
|
513
|
+
// "action" is a reserved keyword in the core runtime; flag any Custom LWC
|
|
514
|
+
// that defines it as a property so the user removes/renames it pre-migration.
|
|
515
|
+
if (Object.prototype.hasOwnProperty.call(component.property, 'action')) {
|
|
516
|
+
const lwcLabel = component.property.customlwcname || component.elementLabel || stringContants_1.Constants.CustomLwc;
|
|
517
|
+
const reservedActionMessage = this.messages.getMessage('customLwcReservedActionKey', [lwcLabel]);
|
|
518
|
+
flexCardAssessmentInfo.errors.push(reservedActionMessage);
|
|
519
|
+
flexCardAssessmentInfo.warnings.push(reservedActionMessage);
|
|
520
|
+
flexCardAssessmentInfo.migrationStatus = 'Needs manual intervention';
|
|
521
|
+
}
|
|
414
522
|
}
|
|
415
523
|
}
|
|
416
524
|
/**
|
|
@@ -573,12 +681,16 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
573
681
|
}
|
|
574
682
|
return childs;
|
|
575
683
|
}
|
|
576
|
-
checkComponentForDependencies(component, flexCardAssessmentInfo) {
|
|
684
|
+
checkComponentForDependencies(component, flexCardAssessmentInfo, omniScriptNavigateURLWarningKeys = new Set()) {
|
|
577
685
|
// Check if this component is an action element
|
|
578
686
|
if (component.element === 'action' && component.property && component.property.actionList) {
|
|
579
687
|
// Process each action in the actionList
|
|
580
688
|
for (const action of component.property.actionList) {
|
|
581
689
|
if (action.stateAction) {
|
|
690
|
+
// Detect Vlocity Action (not supported in standard runtime FlexCards)
|
|
691
|
+
if (action.stateAction.type === stringContants_1.Constants.VlocityAction) {
|
|
692
|
+
this.addVlocityActionDependency(action.stateAction, flexCardAssessmentInfo);
|
|
693
|
+
}
|
|
582
694
|
// Handle message field (contains DataRaptor/IP references as JSON string)
|
|
583
695
|
this.processStateActionMessageForDependencies(action.stateAction, flexCardAssessmentInfo);
|
|
584
696
|
// Case 1: Direct OmniScript reference
|
|
@@ -619,6 +731,9 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
619
731
|
else if (this.hasCustomLwcFlyoutDependency(action.stateAction)) {
|
|
620
732
|
this.addCfPrefixedFlexCardDependency(action.stateAction.flyoutLwc, flexCardAssessmentInfo);
|
|
621
733
|
}
|
|
734
|
+
else if (this.isCustomWebPageAction(action.stateAction)) {
|
|
735
|
+
this.addOmniScriptNavigateURLAssessmentWarning(action.stateAction, flexCardAssessmentInfo, omniScriptNavigateURLWarningKeys);
|
|
736
|
+
}
|
|
622
737
|
}
|
|
623
738
|
}
|
|
624
739
|
}
|
|
@@ -659,6 +774,9 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
659
774
|
if (this.hasCustomLwcFlyoutDependency(component.property.stateAction)) {
|
|
660
775
|
this.addCfPrefixedFlexCardDependency(component.property.stateAction.flyoutLwc, flexCardAssessmentInfo);
|
|
661
776
|
}
|
|
777
|
+
else if (this.isCustomWebPageAction(component.property.stateAction)) {
|
|
778
|
+
this.addOmniScriptNavigateURLAssessmentWarning(component.property.stateAction, flexCardAssessmentInfo, omniScriptNavigateURLWarningKeys);
|
|
779
|
+
}
|
|
662
780
|
}
|
|
663
781
|
// MISSING PATTERN FIXED: Handle omni-flyout elements (from tests)
|
|
664
782
|
if (component.element === stringContants_1.Constants.OmniFlyout && component.property && component.property.flyoutOmniScript) {
|
|
@@ -675,11 +793,80 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
675
793
|
}
|
|
676
794
|
// Check child components recursively
|
|
677
795
|
if (component.children && Array.isArray(component.children)) {
|
|
678
|
-
for (
|
|
679
|
-
|
|
796
|
+
for (let childIndex = 0; childIndex < component.children.length; childIndex++) {
|
|
797
|
+
const child = component.children[childIndex];
|
|
798
|
+
this.checkComponentForDependencies(child, flexCardAssessmentInfo, omniScriptNavigateURLWarningKeys);
|
|
680
799
|
}
|
|
681
800
|
}
|
|
682
801
|
}
|
|
802
|
+
addOmniScriptNavigateURLAssessmentWarning(stateAction, flexCardAssessmentInfo, warningKeys) {
|
|
803
|
+
if (this.IS_STANDARD_DATA_MODEL) {
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
const rewrite = this.getOmniScriptURLRewrite(stateAction);
|
|
807
|
+
if (!rewrite) {
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
const { targetName, updatedURL, malformedTokens } = rewrite;
|
|
811
|
+
const summary = this.formatURLRewriteSummary(targetName, updatedURL);
|
|
812
|
+
if (warningKeys.has(summary)) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
warningKeys.add(summary);
|
|
816
|
+
// Emit a single warning per URL: when fragment tokens are malformed, the
|
|
817
|
+
// dedicated malformed-token warning is the authoritative one (it already
|
|
818
|
+
// contains both the original URL and the "will get replaced with" line,
|
|
819
|
+
// PLUS the malformed-token list and the verify instruction). For clean
|
|
820
|
+
// URLs we fall back to the plain rewrite warning. Defense-in-depth: if
|
|
821
|
+
// the malformed formatter unexpectedly returns empty, fall back to the
|
|
822
|
+
// plain rewrite warning so the customer still sees something.
|
|
823
|
+
const hasMalformedTokens = Array.isArray(malformedTokens) && malformedTokens.length > 0;
|
|
824
|
+
let warningText = '';
|
|
825
|
+
if (hasMalformedTokens) {
|
|
826
|
+
warningText = this.formatMalformedFragmentTokenWarning(targetName, updatedURL, malformedTokens);
|
|
827
|
+
}
|
|
828
|
+
if (!warningText) {
|
|
829
|
+
warningText = this.messages.getMessage('webPageOmniScriptNavigationDetected', [
|
|
830
|
+
this.toReadableURL(targetName),
|
|
831
|
+
this.toReadableURL(updatedURL),
|
|
832
|
+
]);
|
|
833
|
+
}
|
|
834
|
+
flexCardAssessmentInfo.warnings.push(warningText);
|
|
835
|
+
flexCardAssessmentInfo.migrationStatus = (0, stringUtils_1.getUpdatedAssessmentStatus)(flexCardAssessmentInfo.migrationStatus, 'Warnings');
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Build the customer-facing warning shown when a Web Page action URL contains
|
|
839
|
+
* fragment tokens that decodeURIComponent couldn't parse. Centralised here so
|
|
840
|
+
* the assessment and migration paths emit byte-identical text.
|
|
841
|
+
*
|
|
842
|
+
* Returns an empty string when the helper is called with no malformed tokens
|
|
843
|
+
* (defense in depth: callers already guard, but a future caller that forgets
|
|
844
|
+
* shouldn't be able to produce a degenerate warning with an empty bracket).
|
|
845
|
+
* Non-string entries are coerced via String() so a misbehaving caller can't
|
|
846
|
+
* surface "undefined" / "[object Object]" to customers; duplicates are
|
|
847
|
+
* suppressed so a fragment like `#/Foo%/Bar/Foo%/Baz` doesn't render as
|
|
848
|
+
* `["Foo%", "Foo%"]`.
|
|
849
|
+
*/
|
|
850
|
+
formatMalformedFragmentTokenWarning(targetName, updatedURL, malformedTokens) {
|
|
851
|
+
if (!Array.isArray(malformedTokens) || malformedTokens.length === 0) {
|
|
852
|
+
return '';
|
|
853
|
+
}
|
|
854
|
+
const seen = new Set();
|
|
855
|
+
const uniqueTokens = [];
|
|
856
|
+
for (const raw of malformedTokens) {
|
|
857
|
+
const t = typeof raw === 'string' ? raw : String(raw);
|
|
858
|
+
if (!seen.has(t)) {
|
|
859
|
+
seen.add(t);
|
|
860
|
+
uniqueTokens.push(t);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
const tokenList = uniqueTokens.map((t) => `"${t}"`).join(', ');
|
|
864
|
+
return this.messages.getMessage('webPageOmniScriptUrlMalformedToken', [
|
|
865
|
+
tokenList,
|
|
866
|
+
this.toReadableURL(targetName),
|
|
867
|
+
this.toReadableURL(updatedURL),
|
|
868
|
+
]);
|
|
869
|
+
}
|
|
683
870
|
async getAllCards() {
|
|
684
871
|
//DebugTimer.getInstance().lap('Query Vlocity Cards');
|
|
685
872
|
const filters = new Map();
|
|
@@ -752,7 +939,12 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
752
939
|
}
|
|
753
940
|
// Perform the transformation
|
|
754
941
|
const invalidIpNames = new Map();
|
|
755
|
-
const
|
|
942
|
+
const urlUpdateSummaries = new Set();
|
|
943
|
+
// Map keyed by rewrite summary so the emission step below can subtract
|
|
944
|
+
// malformed URLs from the aggregate "Updated URLs:" locations message.
|
|
945
|
+
// Same key for two actions on the same card => one entry (deduped).
|
|
946
|
+
const malformedFragmentWarnings = new Map();
|
|
947
|
+
const transformedCard = this.mapVlocityCardRecord(card, cardsUploadInfo, invalidIpNames, urlUpdateSummaries, malformedFragmentWarnings); // This only has the card structure, card definition is not there
|
|
756
948
|
// Verify duplicated names
|
|
757
949
|
let transformedCardName;
|
|
758
950
|
if (this.allVersions) {
|
|
@@ -822,6 +1014,25 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
822
1014
|
if (transformedCard['Name'] !== card['Name']) {
|
|
823
1015
|
uploadResult.warnings.unshift(this.messages.getMessage('cardNameChangeMessage', [transformedCardName]));
|
|
824
1016
|
}
|
|
1017
|
+
// The count summary describes ONLY URLs that were converted cleanly
|
|
1018
|
+
// to the standard URL format. Malformed URLs were rewritten with
|
|
1019
|
+
// their bad tokens kept as-is -- claiming they were "updated to
|
|
1020
|
+
// standard URL format" alongside their own malformed warning would
|
|
1021
|
+
// contradict that warning and confuse the customer. Each malformed
|
|
1022
|
+
// URL is surfaced via its own dedicated bullet below which already
|
|
1023
|
+
// names the original URL, the rewritten URL, and the verify
|
|
1024
|
+
// instruction.
|
|
1025
|
+
const cleanRewriteSummaries = Array.from(urlUpdateSummaries).filter((summary) => !malformedFragmentWarnings.has(summary));
|
|
1026
|
+
if (cleanRewriteSummaries.length > 0) {
|
|
1027
|
+
uploadResult.warnings.unshift(this.messages.getMessage('flexCardOmniScriptNavigateURLUpdated', [String(cleanRewriteSummaries.length)]));
|
|
1028
|
+
}
|
|
1029
|
+
// Surface malformed-fragment-token warnings (one per affected URL).
|
|
1030
|
+
// These are intentionally emitted *instead of* the count bullet
|
|
1031
|
+
// above so the customer sees a single, actionable bullet per
|
|
1032
|
+
// malformed URL: original URL, rewrite, verify instruction.
|
|
1033
|
+
for (const malformedWarning of malformedFragmentWarnings.values()) {
|
|
1034
|
+
uploadResult.warnings.push(malformedWarning);
|
|
1035
|
+
}
|
|
825
1036
|
if (uploadResult.id && invalidIpNames.size > 0) {
|
|
826
1037
|
const val = Array.from(invalidIpNames.entries())
|
|
827
1038
|
.map((e) => e[0])
|
|
@@ -1002,7 +1213,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1002
1213
|
card[this.getFieldKey('Definition__c')] = JSON.stringify(definition);
|
|
1003
1214
|
}
|
|
1004
1215
|
// Maps an indivitdual VlocityCard__c record to an OmniUiCard record.
|
|
1005
|
-
mapVlocityCardRecord(cardRecord, cardsUploadInfo, invalidIpNames) {
|
|
1216
|
+
mapVlocityCardRecord(cardRecord, cardsUploadInfo, invalidIpNames, urlUpdateSummaries, malformedFragmentWarnings) {
|
|
1006
1217
|
var _a, _b;
|
|
1007
1218
|
// Transformed object
|
|
1008
1219
|
let mappedObject = {};
|
|
@@ -1082,7 +1293,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1082
1293
|
const isCardActive = cardRecord[this.getFieldKey('Active__c')];
|
|
1083
1294
|
this.ensureCommunityTargets(mappedObject, isCardActive);
|
|
1084
1295
|
// Update all dependencies comprehensively
|
|
1085
|
-
this.updateAllDependenciesWithRegistry(mappedObject, invalidIpNames);
|
|
1296
|
+
this.updateAllDependenciesWithRegistry(mappedObject, invalidIpNames, urlUpdateSummaries, malformedFragmentWarnings);
|
|
1086
1297
|
mappedObject['attributes'] = {
|
|
1087
1298
|
type: CardMigrationTool.OMNIUICARD_NAME,
|
|
1088
1299
|
referenceId: cardRecord['Id'],
|
|
@@ -1092,7 +1303,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1092
1303
|
/**
|
|
1093
1304
|
* Comprehensive dependency update using NameMappingRegistry - mirrors assessment logic
|
|
1094
1305
|
*/
|
|
1095
|
-
updateAllDependenciesWithRegistry(mappedObject, invalidIpNames) {
|
|
1306
|
+
updateAllDependenciesWithRegistry(mappedObject, invalidIpNames, urlUpdateSummaries, malformedFragmentWarnings) {
|
|
1096
1307
|
// Handle propertySet (Definition) - update all dependency references
|
|
1097
1308
|
const propertySet = JSON.parse(mappedObject[VlocityCard_1.default.Definition__c] || '{}');
|
|
1098
1309
|
if (propertySet) {
|
|
@@ -1127,7 +1338,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1127
1338
|
for (const componentKey in state.components) {
|
|
1128
1339
|
if (state.components.hasOwnProperty(componentKey)) {
|
|
1129
1340
|
const component = state.components[componentKey];
|
|
1130
|
-
this.updateComponentDependenciesWithRegistry(component);
|
|
1341
|
+
this.updateComponentDependenciesWithRegistry(component, urlUpdateSummaries, malformedFragmentWarnings);
|
|
1131
1342
|
}
|
|
1132
1343
|
}
|
|
1133
1344
|
}
|
|
@@ -1183,7 +1394,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1183
1394
|
* Update dataSource (DataRaptor, Integration Procedures, Apex Remote) using registry
|
|
1184
1395
|
*/
|
|
1185
1396
|
updateDataSourceWithRegistry(dataSource, invalidIpNames, context) {
|
|
1186
|
-
var _a, _b;
|
|
1397
|
+
var _a, _b, _c;
|
|
1187
1398
|
const type = dataSource.type;
|
|
1188
1399
|
if (type === stringContants_1.Constants.DataRaptorComponentName) {
|
|
1189
1400
|
// Handle DataRaptor using registry
|
|
@@ -1214,6 +1425,11 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1214
1425
|
}
|
|
1215
1426
|
}
|
|
1216
1427
|
}
|
|
1428
|
+
else if (type === stringContants_1.Constants.ApexRemoteComponentName) {
|
|
1429
|
+
if ((_c = dataSource.value) === null || _c === void 0 ? void 0 : _c.remoteClass) {
|
|
1430
|
+
dataSource.value.remoteClass = this.apexNamespaceRegistry.getQualifiedClassName(dataSource.value.remoteClass);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1217
1433
|
}
|
|
1218
1434
|
/**
|
|
1219
1435
|
* Update OmniScript reference using registry
|
|
@@ -1247,7 +1463,7 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1247
1463
|
/**
|
|
1248
1464
|
* Update component dependencies comprehensively
|
|
1249
1465
|
*/
|
|
1250
|
-
updateComponentDependenciesWithRegistry(component) {
|
|
1466
|
+
updateComponentDependenciesWithRegistry(component, urlUpdateSummaries, malformedFragmentWarnings) {
|
|
1251
1467
|
// Handle action elements with actionList (like assessment)
|
|
1252
1468
|
if (component.element === 'action' && component.property && component.property.actionList) {
|
|
1253
1469
|
for (const action of component.property.actionList) {
|
|
@@ -1266,6 +1482,10 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1266
1482
|
else if (this.hasFlyoutLwc(action.stateAction)) {
|
|
1267
1483
|
this.updateFlyoutLwcValue(action.stateAction);
|
|
1268
1484
|
}
|
|
1485
|
+
// Case A: Custom Web Page action referencing OmniScript Universal Page
|
|
1486
|
+
else if (this.isCustomWebPageAction(action.stateAction)) {
|
|
1487
|
+
this.applyOmniScriptURLRewrite(action.stateAction, urlUpdateSummaries, malformedFragmentWarnings);
|
|
1488
|
+
}
|
|
1269
1489
|
}
|
|
1270
1490
|
}
|
|
1271
1491
|
}
|
|
@@ -1291,6 +1511,9 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1291
1511
|
if (this.hasFlyoutLwc(component.property.stateAction)) {
|
|
1292
1512
|
this.updateFlyoutLwcValue(component.property.stateAction);
|
|
1293
1513
|
}
|
|
1514
|
+
if (this.isCustomWebPageAction(component.property.stateAction)) {
|
|
1515
|
+
this.applyOmniScriptURLRewrite(component.property.stateAction, urlUpdateSummaries, malformedFragmentWarnings);
|
|
1516
|
+
}
|
|
1294
1517
|
}
|
|
1295
1518
|
// Handle childCardPreview elements (from old fixChildren method)
|
|
1296
1519
|
if (component.element === stringContants_1.Constants.ChildCardPreview && component.property) {
|
|
@@ -1337,9 +1560,201 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1337
1560
|
// Check child components recursively
|
|
1338
1561
|
if (component.children && Array.isArray(component.children)) {
|
|
1339
1562
|
for (const child of component.children) {
|
|
1340
|
-
this.updateComponentDependenciesWithRegistry(child);
|
|
1563
|
+
this.updateComponentDependenciesWithRegistry(child, urlUpdateSummaries, malformedFragmentWarnings);
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1567
|
+
applyOmniScriptURLRewrite(stateAction, urlUpdateSummaries, malformedFragmentWarnings) {
|
|
1568
|
+
if (this.IS_STANDARD_DATA_MODEL) {
|
|
1569
|
+
return;
|
|
1570
|
+
}
|
|
1571
|
+
const rewrite = this.getOmniScriptURLRewrite(stateAction);
|
|
1572
|
+
if (!rewrite) {
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
const { targetName, updatedURL, malformedTokens } = rewrite;
|
|
1576
|
+
stateAction[stringContants_1.Constants.WebPageTargetType].targetName = updatedURL;
|
|
1577
|
+
const summary = this.formatURLRewriteSummary(targetName, updatedURL);
|
|
1578
|
+
urlUpdateSummaries.add(summary);
|
|
1579
|
+
// Per-card collector is optional so internal/test callers can omit it
|
|
1580
|
+
// without forcing a signature update. The Map is keyed by the rewrite
|
|
1581
|
+
// summary so the emission step can later subtract malformed URLs from
|
|
1582
|
+
// the aggregate "Updated URLs: ..." locations message -- each malformed
|
|
1583
|
+
// entry already carries the original URL, the rewritten URL, and the
|
|
1584
|
+
// verify instruction inside its own warning, so listing it twice would
|
|
1585
|
+
// be redundant. Same key for two actions on the same card => one entry.
|
|
1586
|
+
// Defense-in-depth: skip if the formatter returns an empty string so we
|
|
1587
|
+
// never store a blank warning under a real summary key.
|
|
1588
|
+
if (malformedFragmentWarnings && Array.isArray(malformedTokens) && malformedTokens.length > 0) {
|
|
1589
|
+
const malformedWarning = this.formatMalformedFragmentTokenWarning(targetName, updatedURL, malformedTokens);
|
|
1590
|
+
if (malformedWarning) {
|
|
1591
|
+
malformedFragmentWarnings.set(summary, malformedWarning);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
/** Build a human-readable "before -> after" string for warning messages only. */
|
|
1596
|
+
formatURLRewriteSummary(originalURL, updatedURL) {
|
|
1597
|
+
return `${this.toReadableURL(originalURL)} -> ${this.toReadableURL(updatedURL)}`;
|
|
1598
|
+
}
|
|
1599
|
+
/**
|
|
1600
|
+
* Decode a URL for DISPLAY purposes only (warning/log messages). The output
|
|
1601
|
+
* is lossy with respect to URL parsing semantics (e.g. an encoded `%26`
|
|
1602
|
+
* becomes a literal `&`) and must NOT be re-fed into a URL parser. Falls
|
|
1603
|
+
* back to the raw input on malformed percent sequences.
|
|
1604
|
+
*/
|
|
1605
|
+
toReadableURL(url) {
|
|
1606
|
+
try {
|
|
1607
|
+
return decodeURIComponent(url);
|
|
1608
|
+
}
|
|
1609
|
+
catch {
|
|
1610
|
+
return url;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
getOmniScriptURLRewrite(stateAction) {
|
|
1614
|
+
var _a;
|
|
1615
|
+
const targetName = (_a = stateAction[stringContants_1.Constants.WebPageTargetType]) === null || _a === void 0 ? void 0 : _a.targetName;
|
|
1616
|
+
if (typeof targetName !== 'string') {
|
|
1617
|
+
return undefined;
|
|
1618
|
+
}
|
|
1619
|
+
// Fast reject: if the raw text doesn't even mention the universal-page
|
|
1620
|
+
// path or token, skip URL parsing entirely. This is a substring screen,
|
|
1621
|
+
// not a security check; the strict structural validation happens after
|
|
1622
|
+
// parsing in isValidOmniScriptNavigationURL.
|
|
1623
|
+
if (!targetName.includes(stringContants_1.Constants.OmniScriptUniversalPagePath) ||
|
|
1624
|
+
!targetName.includes(stringContants_1.Constants.OmniScriptUniversalPageToken)) {
|
|
1625
|
+
return undefined;
|
|
1626
|
+
}
|
|
1627
|
+
const parsedURL = this.tryParseURL(targetName);
|
|
1628
|
+
if (!parsedURL || !this.isValidOmniScriptNavigationURL(parsedURL)) {
|
|
1629
|
+
return undefined;
|
|
1630
|
+
}
|
|
1631
|
+
const updatedURL = this.convertToStandardOmniScriptURL(parsedURL);
|
|
1632
|
+
// Re-parse the fragment once more here purely to capture malformed-token
|
|
1633
|
+
// diagnostics for the caller. Cheap (single split + map over a short
|
|
1634
|
+
// string) and keeps `convertToStandardOmniScriptURL` focused on rewriting.
|
|
1635
|
+
const { malformedTokens } = this.parseSlashFragmentParams(parsedURL.hash);
|
|
1636
|
+
return { targetName, updatedURL, malformedTokens };
|
|
1637
|
+
}
|
|
1638
|
+
isCustomWebPageAction(stateAction) {
|
|
1639
|
+
return (stateAction === null || stateAction === void 0 ? void 0 : stateAction.type) === stringContants_1.Constants.CustomActionType && (stateAction === null || stateAction === void 0 ? void 0 : stateAction.targetType) === stringContants_1.Constants.WebPageTargetType;
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Parse a URL string without throwing. Returns the parsed URL on success or
|
|
1643
|
+
* undefined for:
|
|
1644
|
+
* - syntactically invalid input (e.g. `https://[bad`, raw spaces in host,
|
|
1645
|
+
* `http:///` with no host), or
|
|
1646
|
+
* - URLs whose scheme is not `http:` or `https:` (e.g. `javascript:`,
|
|
1647
|
+
* `data:`, `file:`, `mailto:`).
|
|
1648
|
+
*
|
|
1649
|
+
* See URL_PARSE_BASE for why a synthetic base is supplied.
|
|
1650
|
+
*/
|
|
1651
|
+
tryParseURL(input) {
|
|
1652
|
+
let parsed;
|
|
1653
|
+
try {
|
|
1654
|
+
parsed = new URL(input, CardMigrationTool.URL_PARSE_BASE);
|
|
1655
|
+
}
|
|
1656
|
+
catch {
|
|
1657
|
+
return undefined;
|
|
1658
|
+
}
|
|
1659
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
1660
|
+
return undefined;
|
|
1661
|
+
}
|
|
1662
|
+
return parsed;
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Verify a parsed URL has the OmniScript Navigate shape. We validate against
|
|
1666
|
+
* the parsed components (pathname / searchParams / hash) rather than doing
|
|
1667
|
+
* substring matches on the raw input so callers cannot smuggle the required
|
|
1668
|
+
* tokens in unrelated positions (e.g. inside another query value).
|
|
1669
|
+
*
|
|
1670
|
+
* The pathname must START WITH `/apex/` and contain the universal-page
|
|
1671
|
+
* token. Anchoring to the prefix rejects non-http(s) schemes such as
|
|
1672
|
+
* `javascript:alert(1)//apex/...` whose parsed pathname does not begin
|
|
1673
|
+
* with `/` (it begins with the opaque body of the scheme).
|
|
1674
|
+
*
|
|
1675
|
+
* Two legitimate shapes are accepted:
|
|
1676
|
+
* 1. Path + query: /apex/<ns>__OmniScriptUniversalPage?OmniScriptType=...&OmniScriptSubType=...&OmniScriptLang=...
|
|
1677
|
+
* 2. Path + fragment: /apex/<ns>__OmniScriptUniversalPage?...#/OmniScriptType/.../OmniScriptSubType/.../OmniScriptLang/...
|
|
1678
|
+
*/
|
|
1679
|
+
isValidOmniScriptNavigationURL(parsedURL) {
|
|
1680
|
+
if (!parsedURL.pathname.startsWith(`${stringContants_1.Constants.OmniScriptUniversalPagePath}/`)) {
|
|
1681
|
+
return false;
|
|
1682
|
+
}
|
|
1683
|
+
if (!parsedURL.pathname.includes(stringContants_1.Constants.OmniScriptUniversalPageToken)) {
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
const fragmentKeys = new Set(this.parseSlashFragmentParams(parsedURL.hash).pairs.map(([key]) => key));
|
|
1687
|
+
const hasParam = (key) => parsedURL.searchParams.has(key) || fragmentKeys.has(key);
|
|
1688
|
+
return (hasParam(stringContants_1.Constants.OmniScriptTypeParam) &&
|
|
1689
|
+
hasParam(stringContants_1.Constants.OmniScriptSubTypeParam) &&
|
|
1690
|
+
hasParam(stringContants_1.Constants.OmniScriptLangParam));
|
|
1691
|
+
}
|
|
1692
|
+
convertToStandardOmniScriptURL(parsedURL) {
|
|
1693
|
+
var _a;
|
|
1694
|
+
const paramRenames = {
|
|
1695
|
+
[stringContants_1.Constants.OmniScriptTypeParam]: stringContants_1.Constants.OmniScriptStandardTypeParam,
|
|
1696
|
+
[stringContants_1.Constants.OmniScriptSubTypeParam]: stringContants_1.Constants.OmniScriptStandardSubTypeParam,
|
|
1697
|
+
[stringContants_1.Constants.OmniScriptLangParam]: stringContants_1.Constants.OmniScriptStandardLanguageParam,
|
|
1698
|
+
[stringContants_1.Constants.OmniScriptLayoutParam]: stringContants_1.Constants.OmniScriptStandardThemeParam,
|
|
1699
|
+
};
|
|
1700
|
+
const paramsToClean = new Set([stringContants_1.Constants.OmniScriptTypeParam, stringContants_1.Constants.OmniScriptSubTypeParam]);
|
|
1701
|
+
// Merge query-string params with fragment params. Query-string entries win on conflict.
|
|
1702
|
+
const mergedEntries = [];
|
|
1703
|
+
const seenKeys = new Set();
|
|
1704
|
+
parsedURL.searchParams.forEach((value, key) => {
|
|
1705
|
+
mergedEntries.push([key, value]);
|
|
1706
|
+
seenKeys.add(key);
|
|
1707
|
+
});
|
|
1708
|
+
for (const [key, value] of this.parseSlashFragmentParams(parsedURL.hash).pairs) {
|
|
1709
|
+
if (!seenKeys.has(key)) {
|
|
1710
|
+
mergedEntries.push([key, value]);
|
|
1711
|
+
seenKeys.add(key);
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
const newSearchParams = new URLSearchParams();
|
|
1715
|
+
for (const [key, value] of mergedEntries) {
|
|
1716
|
+
const newKey = (_a = paramRenames[key]) !== null && _a !== void 0 ? _a : key;
|
|
1717
|
+
const newValue = paramsToClean.has(key) ? this.cleanName(value) : value;
|
|
1718
|
+
newSearchParams.append(newKey, newValue);
|
|
1719
|
+
}
|
|
1720
|
+
return `${stringContants_1.Constants.OmniScriptStandardPagePath}?${newSearchParams.toString()}`;
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Parse a slash-separated OmniScript fragment of the form
|
|
1724
|
+
* #/Key1/Value1/Key2/Value2/...
|
|
1725
|
+
* into [key, value] pairs. Tolerates leading `#`, leading `/`, empty values
|
|
1726
|
+
* (consecutive slashes), and a trailing orphan token (which is dropped).
|
|
1727
|
+
*
|
|
1728
|
+
* Tokens with malformed percent sequences (e.g. `Foo%`, `Bar%E2`) are kept
|
|
1729
|
+
* as-is rather than throwing; decodeURIComponent raises URIError on invalid
|
|
1730
|
+
* escape sequences and we don't want one bad token to crash the whole
|
|
1731
|
+
* FlexCard's URL rewrite. The raw (still-encoded) tokens are also returned
|
|
1732
|
+
* via `malformedTokens` so callers can surface them to customers as a
|
|
1733
|
+
* "please verify" warning rather than silently shipping a best-effort guess.
|
|
1734
|
+
*/
|
|
1735
|
+
parseSlashFragmentParams(hash) {
|
|
1736
|
+
if (!hash) {
|
|
1737
|
+
return { pairs: [], malformedTokens: [] };
|
|
1738
|
+
}
|
|
1739
|
+
const trimmed = hash.replace(/^#\/?/, '');
|
|
1740
|
+
if (!trimmed) {
|
|
1741
|
+
return { pairs: [], malformedTokens: [] };
|
|
1742
|
+
}
|
|
1743
|
+
const malformedTokens = [];
|
|
1744
|
+
const tokens = trimmed.split('/').map((t) => {
|
|
1745
|
+
try {
|
|
1746
|
+
return decodeURIComponent(t);
|
|
1747
|
+
}
|
|
1748
|
+
catch {
|
|
1749
|
+
malformedTokens.push(t);
|
|
1750
|
+
return t;
|
|
1341
1751
|
}
|
|
1752
|
+
});
|
|
1753
|
+
const pairs = [];
|
|
1754
|
+
for (let i = 0; i + 1 < tokens.length; i += 2) {
|
|
1755
|
+
pairs.push([tokens[i], tokens[i + 1]]);
|
|
1342
1756
|
}
|
|
1757
|
+
return { pairs, malformedTokens };
|
|
1343
1758
|
}
|
|
1344
1759
|
/**
|
|
1345
1760
|
* Update omniType.Name using registry (handles Type/SubType/Language format)
|
|
@@ -1517,6 +1932,23 @@ class CardMigrationTool extends base_1.BaseMigrationTool {
|
|
|
1517
1932
|
flexCardAssessmentInfo.migrationStatus = (0, stringUtils_1.getUpdatedAssessmentStatus)(flexCardAssessmentInfo.migrationStatus, 'Warnings');
|
|
1518
1933
|
}
|
|
1519
1934
|
}
|
|
1935
|
+
/**
|
|
1936
|
+
* Helper method to flag a Vlocity Action dependency during assessment.
|
|
1937
|
+
* Vlocity Actions are not supported in standard runtime FlexCards, so the
|
|
1938
|
+
* FlexCard cannot be auto-migrated and must be manually reimplemented using
|
|
1939
|
+
* the FlexCard Action (cardAction) feature.
|
|
1940
|
+
*/
|
|
1941
|
+
addVlocityActionDependency(stateAction, flexCardAssessmentInfo) {
|
|
1942
|
+
const actionName = stateAction.name || stateAction.displayName || 'Unnamed Vlocity Action';
|
|
1943
|
+
if (!flexCardAssessmentInfo.dependenciesVlocityAction.includes(actionName)) {
|
|
1944
|
+
flexCardAssessmentInfo.dependenciesVlocityAction.push(actionName);
|
|
1945
|
+
}
|
|
1946
|
+
const warning = this.messages.getMessage('vlocityActionNotSupportedMessage', [actionName]);
|
|
1947
|
+
if (!flexCardAssessmentInfo.warnings.includes(warning)) {
|
|
1948
|
+
flexCardAssessmentInfo.warnings.push(warning);
|
|
1949
|
+
}
|
|
1950
|
+
flexCardAssessmentInfo.migrationStatus = (0, stringUtils_1.getUpdatedAssessmentStatus)(flexCardAssessmentInfo.migrationStatus, 'Needs manual intervention');
|
|
1951
|
+
}
|
|
1520
1952
|
// ==================== End Assessment Helper Methods ====================
|
|
1521
1953
|
getCardFields() {
|
|
1522
1954
|
return this.IS_STANDARD_DATA_MODEL
|
|
@@ -1789,4 +2221,5 @@ exports.CardMigrationTool = CardMigrationTool;
|
|
|
1789
2221
|
CardMigrationTool.VLOCITYCARD_NAME = 'VlocityCard__c';
|
|
1790
2222
|
CardMigrationTool.OMNIUICARD_NAME = 'OmniUiCard';
|
|
1791
2223
|
CardMigrationTool.VERSION_PROP = 'Version__c';
|
|
2224
|
+
CardMigrationTool.URL_PARSE_BASE = 'https://placeholder.local';
|
|
1792
2225
|
//# sourceMappingURL=flexcard.js.map
|