@salesforce/plugin-bre-to-cml 1.1.4 → 1.2.4
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 +27 -9
- package/lib/commands/cml/convert/surcharge-rules.d.ts +19 -3
- package/lib/commands/cml/convert/surcharge-rules.js +94 -13
- package/lib/commands/cml/convert/surcharge-rules.js.map +1 -1
- package/lib/commands/cml/convert/underwriting-rules.d.ts +16 -4
- package/lib/commands/cml/convert/underwriting-rules.js +37 -40
- package/lib/commands/cml/convert/underwriting-rules.js.map +1 -1
- package/lib/shared/insurance/insurance-cml-merge.d.ts +91 -0
- package/lib/shared/insurance/insurance-cml-merge.js +569 -0
- package/lib/shared/insurance/insurance-cml-merge.js.map +1 -0
- package/lib/shared/insurance/insurance-org.d.ts +19 -1
- package/lib/shared/insurance/insurance-org.js +9 -1
- package/lib/shared/insurance/insurance-org.js.map +1 -1
- package/lib/shared/insurance/insurance-rule-convert-command.d.ts +46 -2
- package/lib/shared/insurance/insurance-rule-convert-command.js +213 -22
- package/lib/shared/insurance/insurance-rule-convert-command.js.map +1 -1
- package/lib/shared/insurance/insurance-rule-generator.d.ts +38 -1
- package/lib/shared/insurance/insurance-rule-generator.js +165 -6
- package/lib/shared/insurance/insurance-rule-generator.js.map +1 -1
- package/lib/shared/insurance/models.d.ts +25 -0
- package/messages/cml.convert.insurance-shared.md +9 -1
- package/messages/cml.convert.surcharge-rules.md +1 -1
- package/messages/cml.convert.underwriting-rules.md +1 -1
- package/oclif.lock +294 -706
- package/oclif.manifest.json +5 -5
- package/package.json +10 -10
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
2
|
import { Connection, Org } from '@salesforce/core';
|
|
3
|
-
import { ParsedRuleDefinition, RuleKeyEntry, RuleRecord } from './models.js';
|
|
3
|
+
import { ParsedRuleDefinition, RecordUpdate, RecordUpdatePlan, RuleKeyEntry, RuleRecord } from './models.js';
|
|
4
4
|
export type InsuranceRuleConvertResult = {
|
|
5
5
|
cmlFile: string;
|
|
6
6
|
associationsFile: string;
|
|
7
7
|
ruleKeyMapping: RuleKeyEntry[];
|
|
8
|
+
recordUpdateFile?: string;
|
|
8
9
|
};
|
|
9
10
|
export type InsuranceRuleConvertContext = {
|
|
10
11
|
targetOrg: Org;
|
|
@@ -13,6 +14,11 @@ export type InsuranceRuleConvertContext = {
|
|
|
13
14
|
workspaceDir: string | undefined;
|
|
14
15
|
inputFile: string | undefined;
|
|
15
16
|
updateRecords: boolean;
|
|
17
|
+
mergeWithOrg?: boolean;
|
|
18
|
+
};
|
|
19
|
+
export type ParsedRuleEntry = {
|
|
20
|
+
record: RuleRecord;
|
|
21
|
+
ruleDef: ParsedRuleDefinition;
|
|
16
22
|
};
|
|
17
23
|
export declare abstract class InsuranceRuleConvertCommand<R extends RuleRecord> extends SfCommand<InsuranceRuleConvertResult> {
|
|
18
24
|
static readonly flags: {
|
|
@@ -22,17 +28,55 @@ export declare abstract class InsuranceRuleConvertCommand<R extends RuleRecord>
|
|
|
22
28
|
'workspace-dir': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
29
|
'update-records': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
24
30
|
};
|
|
31
|
+
protected readonly ruleType?: string;
|
|
25
32
|
protected abstract readonly recordLabel: string;
|
|
26
33
|
protected abstract readonly keyPrefix: string;
|
|
27
34
|
protected abstract readonly constraintLabel: string;
|
|
28
35
|
protected abstract readonly apiNamePrefix: string;
|
|
29
36
|
protected abstract readonly soql: string;
|
|
37
|
+
/** Discriminator that selects the on-disk file kind and name suffix for the emitted update file. */
|
|
38
|
+
protected abstract readonly recordUpdateKind: RecordUpdatePlan['kind'];
|
|
30
39
|
protected runConvert(ctx: InsuranceRuleConvertContext): Promise<InsuranceRuleConvertResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Merge-mode entry point. The default errors because merging only makes sense for rule-statement
|
|
42
|
+
* subclasses (surcharge); constraint-form subclasses (underwriting) leave it unimplemented.
|
|
43
|
+
*/
|
|
44
|
+
protected runMergeConvert(ctx: InsuranceRuleConvertContext, conn: Connection, records: R[], ruleDefs: ParsedRuleEntry[], productIdToCode: Map<string, string>, api: string, safeApi: string, workspaceDir: string): Promise<InsuranceRuleConvertResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Writes the merged outputs: the full merged CML, a header-only associations CSV (merge mode
|
|
47
|
+
* touches only existing type blocks, so no new Type associations are needed — but the common
|
|
48
|
+
* import errors on an empty CSV, so the header line must be present), and the rule-key mapping.
|
|
49
|
+
*/
|
|
50
|
+
protected writeMergedOutputFiles(mergedCml: string, ruleKeyMapping: RuleKeyEntry[], safeApi: string, workspaceDir: string, api: string, recordUpdateFile: string): Promise<InsuranceRuleConvertResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Build the record-update plan envelope and write it to `<safeApi>_<kind>Update.json`. This is the
|
|
53
|
+
* ONLY way org-record changes leave convert now — convert never writes to the org itself. The file
|
|
54
|
+
* is a reviewable manifest the operator applies to the org separately; this plugin does not apply it.
|
|
55
|
+
*/
|
|
56
|
+
protected writeRecordUpdateFile(records: R[], ruleKeyMapping: RuleKeyEntry[], api: string, safeApi: string, workspaceDir: string): Promise<string>;
|
|
31
57
|
private loadRecords;
|
|
32
58
|
private parseAllRecords;
|
|
33
59
|
private resolveProductCodes;
|
|
60
|
+
/**
|
|
61
|
+
* Validates the Id -> Name map that feeds each Type association's reference value, mutating it in
|
|
62
|
+
* place so only safe, importer-resolvable Names survive. The Name is written into the naive
|
|
63
|
+
* comma-joined associations CSV and, downstream, into the common importer's single-quoted SOQL
|
|
64
|
+
* `WHERE Name IN ('<Name>')`. Two hazards, neither of which we can fix in the (Rev-Cloud-owned)
|
|
65
|
+
* importer. Unsafe characters (comma, quote, backslash, newline) corrupt the CSV column or break
|
|
66
|
+
* out of the SOQL literal — such a Name is dropped from the map (the generator falls back to the
|
|
67
|
+
* ProductCode) and warned, so the association may not resolve but the output stays valid and
|
|
68
|
+
* injection-free instead of silently wrong. Duplicate Names across distinct product ids make the
|
|
69
|
+
* importer's by-Name lookup ambiguous (last-writer-wins), so a Type could bind to the wrong
|
|
70
|
+
* Product2 — we warn but keep the entries; the documented precondition is that Product Name is
|
|
71
|
+
* unique per migration scope.
|
|
72
|
+
*/
|
|
73
|
+
private validateAssociationNames;
|
|
34
74
|
private discoverCmlApi;
|
|
35
75
|
private writeOutputFiles;
|
|
36
76
|
protected abstract parseRecord(record: R): ParsedRuleDefinition | null;
|
|
37
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Pure transform: given the parsed records and the rule-key mapping, return the list of org-record
|
|
79
|
+
* changes convert WOULD have made. No org writes — the result is serialized into the update file.
|
|
80
|
+
*/
|
|
81
|
+
protected abstract buildRecordUpdates(records: R[], ruleKeyMapping: RuleKeyEntry[]): RecordUpdate[];
|
|
38
82
|
}
|
|
@@ -17,13 +17,25 @@
|
|
|
17
17
|
// This file is a shared abstract base, not a user-invocable command, so the
|
|
18
18
|
// command-shape lint rules do not apply.
|
|
19
19
|
import * as fs from 'node:fs/promises';
|
|
20
|
+
import * as path from 'node:path';
|
|
20
21
|
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
|
|
21
22
|
import { Messages } from '@salesforce/core';
|
|
22
23
|
import { generateCsvForAssociations } from '../utils/association.utils.js';
|
|
23
|
-
import { buildCmlModel } from './insurance-rule-generator.js';
|
|
24
|
+
import { buildCmlModel, isSafeAssociationReferenceValue, sanitizeName } from './insurance-rule-generator.js';
|
|
24
25
|
import { discoverCmlApiByProducts, fetchProductCodes } from './insurance-org.js';
|
|
26
|
+
import { splitProductPath } from './insurance-cml-merge.js';
|
|
25
27
|
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
26
28
|
const messages = Messages.loadMessages('@salesforce/plugin-bre-to-cml', 'cml.convert.insurance-shared');
|
|
29
|
+
// Header row for the header-only `_Associations.csv` the merge path writes (merge mode creates no
|
|
30
|
+
// new Type associations). Kept here in the insurance layer — the common association util owns the
|
|
31
|
+
// build-path CSV and its own copy of this header.
|
|
32
|
+
const ASSOCIATIONS_CSV_HEADER = 'ExpressionSet.ApiName,ConstraintModelTag,ConstraintModelTagType,ReferenceObjectId,$Product2ReferenceId,$ProductClassificationName,$ProductRelatedComponentKey';
|
|
33
|
+
// File-name suffix per record-update kind. The convert commands emit `<safeApi>_<suffix>.json` as a
|
|
34
|
+
// reviewable manifest of the org-record changes; this plugin does NOT apply it (convert is file-only).
|
|
35
|
+
const RECORD_UPDATE_FILE_SUFFIX = {
|
|
36
|
+
'underwriting-update': 'UnderwritingUpdate',
|
|
37
|
+
'surcharge-update': 'SurchargeUpdate',
|
|
38
|
+
};
|
|
27
39
|
export class InsuranceRuleConvertCommand extends SfCommand {
|
|
28
40
|
static flags = {
|
|
29
41
|
'target-org': Flags.requiredOrg(),
|
|
@@ -42,31 +54,128 @@ export class InsuranceRuleConvertCommand extends SfCommand {
|
|
|
42
54
|
default: false,
|
|
43
55
|
}),
|
|
44
56
|
};
|
|
57
|
+
// When defined, eligibility is emitted as a CML `rule(...)` statement tagged with this rule
|
|
58
|
+
// type instead of a `constraint`. Subclasses that want the constraint form leave it undefined.
|
|
59
|
+
ruleType;
|
|
45
60
|
async runConvert(ctx) {
|
|
61
|
+
// Tripwire: convert is now strictly file-only. The legacy --update-records flag mutated the org
|
|
62
|
+
// as a side effect; it is removed, and passing it errors with a pointer to the new flow.
|
|
63
|
+
if (ctx.updateRecords) {
|
|
64
|
+
throw messages.createError('error.updateRecordsRemoved');
|
|
65
|
+
}
|
|
46
66
|
const workspaceDir = ctx.workspaceDir ?? '.';
|
|
47
67
|
this.log(`Using Workspace Directory: ${ctx.workspaceDir ?? 'not specified'}`);
|
|
48
68
|
const conn = ctx.targetOrg.getConnection(ctx.apiVersion);
|
|
49
69
|
const records = await this.loadRecords(conn, ctx.inputFile);
|
|
50
70
|
if (records.length === 0) {
|
|
51
71
|
this.log(`No ${this.recordLabel} rules to convert.`);
|
|
72
|
+
// Still emit an (empty) record-update manifest when we can name it, so automation always has a
|
|
73
|
+
// concrete file to consume. Without --cml-api there are no products to discover an API name
|
|
74
|
+
// from, so there is nothing to name the file after.
|
|
75
|
+
if (ctx.cmlApi) {
|
|
76
|
+
const safeApi = ctx.cmlApi.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
77
|
+
const recordUpdateFile = await this.writeRecordUpdateFile([], [], ctx.cmlApi, safeApi, workspaceDir);
|
|
78
|
+
return { cmlFile: '', associationsFile: '', ruleKeyMapping: [], recordUpdateFile };
|
|
79
|
+
}
|
|
52
80
|
return { cmlFile: '', associationsFile: '', ruleKeyMapping: [] };
|
|
53
81
|
}
|
|
54
82
|
const ruleDefs = this.parseAllRecords(records);
|
|
55
|
-
const productIdToCode = await this.resolveProductCodes(conn, ruleDefs);
|
|
83
|
+
const { productIdToCode, productIdToName } = await this.resolveProductCodes(conn, ruleDefs);
|
|
56
84
|
const api = ctx.cmlApi ?? (await this.discoverCmlApi(conn, ruleDefs, productIdToCode));
|
|
57
85
|
const safeApi = api.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (ctx.updateRecords) {
|
|
61
|
-
await this.updateOrgRecords(records, ruleKeyMapping, conn);
|
|
86
|
+
if (ctx.mergeWithOrg) {
|
|
87
|
+
return this.runMergeConvert(ctx, conn, records, ruleDefs, productIdToCode, api, safeApi, workspaceDir);
|
|
62
88
|
}
|
|
63
|
-
|
|
89
|
+
const { cmlModel, ruleKeyMapping } = buildCmlModel(ruleDefs, productIdToCode, this.keyPrefix, this.constraintLabel, this.ruleType, productIdToName);
|
|
90
|
+
ruleKeyMapping.forEach((m) => this.log(` -> ${m.name} => ${m.ruleKey}`));
|
|
91
|
+
const recordUpdateFile = await this.writeRecordUpdateFile(records, ruleKeyMapping, api, safeApi, workspaceDir);
|
|
92
|
+
return this.writeOutputFiles(cmlModel, ruleKeyMapping, safeApi, workspaceDir, api, recordUpdateFile);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Merge-mode entry point. The default errors because merging only makes sense for rule-statement
|
|
96
|
+
* subclasses (surcharge); constraint-form subclasses (underwriting) leave it unimplemented.
|
|
97
|
+
*/
|
|
98
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
99
|
+
runMergeConvert(ctx, conn, records, ruleDefs, productIdToCode, api, safeApi, workspaceDir) {
|
|
100
|
+
this.error(`Merge mode is not supported for ${this.recordLabel} rules.`);
|
|
101
|
+
}
|
|
102
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
103
|
+
/**
|
|
104
|
+
* Writes the merged outputs: the full merged CML, a header-only associations CSV (merge mode
|
|
105
|
+
* touches only existing type blocks, so no new Type associations are needed — but the common
|
|
106
|
+
* import errors on an empty CSV, so the header line must be present), and the rule-key mapping.
|
|
107
|
+
*/
|
|
108
|
+
async writeMergedOutputFiles(mergedCml, ruleKeyMapping, safeApi, workspaceDir, api, recordUpdateFile) {
|
|
109
|
+
// [Fix #15] Use path.join so emitted paths use the OS-native separator. Hardcoded '/' template
|
|
110
|
+
// literals produced forward-slash paths on Windows; tests that assert against path.join then
|
|
111
|
+
// diverged at the separator (`\` vs `/`). path.join keeps Linux unchanged ('/' verbatim) and
|
|
112
|
+
// emits backslashes on Windows, matching the test's normalized expectation.
|
|
113
|
+
const cmlPath = path.join(workspaceDir, `${safeApi}.cml`);
|
|
114
|
+
const associationsPath = path.join(workspaceDir, `${safeApi}_Associations.csv`);
|
|
115
|
+
const mappingPath = path.join(workspaceDir, `${safeApi}_RuleKeyMapping.json`);
|
|
116
|
+
await fs.writeFile(cmlPath, mergedCml, 'utf8');
|
|
117
|
+
await fs.writeFile(associationsPath, `${ASSOCIATIONS_CSV_HEADER}\n`, 'utf8');
|
|
118
|
+
await fs.writeFile(mappingPath, JSON.stringify(ruleKeyMapping, null, 2), 'utf8');
|
|
119
|
+
this.log(`\nMerged CML written to: ${cmlPath}`);
|
|
120
|
+
this.log(`Associations (header-only, no new type associations) written to: ${associationsPath}`);
|
|
121
|
+
this.log(`Rule key mapping written to: ${mappingPath}`);
|
|
122
|
+
this.log(`Record update file written to: ${recordUpdateFile}`);
|
|
123
|
+
this.log('\nNext steps (this command wrote nothing to the org):');
|
|
124
|
+
this.log(' 1. Review the merged .cml file (diff against the org model) and the record update file');
|
|
125
|
+
this.log(` 2. Activate the CML: sf cml import as-expression-set --cml-api ${api} --context-definition <CD_NAME> --target-org <org>`);
|
|
126
|
+
this.log(` 3. Apply the org-record changes enumerated in ${recordUpdateFile} to the target org`);
|
|
127
|
+
return { cmlFile: cmlPath, associationsFile: associationsPath, ruleKeyMapping, recordUpdateFile };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Build the record-update plan envelope and write it to `<safeApi>_<kind>Update.json`. This is the
|
|
131
|
+
* ONLY way org-record changes leave convert now — convert never writes to the org itself. The file
|
|
132
|
+
* is a reviewable manifest the operator applies to the org separately; this plugin does not apply it.
|
|
133
|
+
*/
|
|
134
|
+
async writeRecordUpdateFile(records, ruleKeyMapping, api, safeApi, workspaceDir) {
|
|
135
|
+
const plan = {
|
|
136
|
+
schemaVersion: 1,
|
|
137
|
+
kind: this.recordUpdateKind,
|
|
138
|
+
cmlApi: api,
|
|
139
|
+
generatedAt: new Date().toISOString(),
|
|
140
|
+
updates: this.buildRecordUpdates(records, ruleKeyMapping),
|
|
141
|
+
};
|
|
142
|
+
// [Fix #15] path.join for cross-platform path separators (was hardcoded '/'). Note: this local
|
|
143
|
+
// is intentionally named `filePath` rather than `path` to avoid shadowing the `path` module import.
|
|
144
|
+
const filePath = path.join(workspaceDir, `${safeApi}_${RECORD_UPDATE_FILE_SUFFIX[this.recordUpdateKind]}.json`);
|
|
145
|
+
await fs.writeFile(filePath, JSON.stringify(plan, null, 2), 'utf8');
|
|
146
|
+
return filePath;
|
|
64
147
|
}
|
|
65
148
|
async loadRecords(conn, inputFile) {
|
|
66
149
|
if (inputFile) {
|
|
67
150
|
this.log(`Reading ${this.recordLabel} records from file: ${inputFile}`);
|
|
68
151
|
const contents = await fs.readFile(inputFile, 'utf8');
|
|
69
|
-
|
|
152
|
+
let parsed;
|
|
153
|
+
try {
|
|
154
|
+
parsed = JSON.parse(contents);
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
throw new Error(`${inputFile}: not valid JSON (${e.message})`);
|
|
158
|
+
}
|
|
159
|
+
// [Fix #6] The file is operator-supplied input that drives ProductPath splits, SOQL id
|
|
160
|
+
// resolution, and rule-key derivation. A non-array root, or records with missing/non-string
|
|
161
|
+
// Id / Name / ProductPath, would otherwise propagate `undefined`s through the pipeline and
|
|
162
|
+
// surface as confusing downstream failures (or silently malformed output). Refuse upfront.
|
|
163
|
+
if (!Array.isArray(parsed)) {
|
|
164
|
+
throw new Error(`${inputFile}: expected a top-level JSON array of ${this.recordLabel} records`);
|
|
165
|
+
}
|
|
166
|
+
parsed.forEach((entry, index) => {
|
|
167
|
+
if (entry === null || typeof entry !== 'object') {
|
|
168
|
+
throw new Error(`${inputFile}: record #${index} is not an object`);
|
|
169
|
+
}
|
|
170
|
+
const rec = entry;
|
|
171
|
+
for (const field of ['Id', 'Name', 'ProductPath']) {
|
|
172
|
+
const value = rec[field];
|
|
173
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
174
|
+
throw new Error(`${inputFile}: record #${index} has missing or non-string ${field}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
return parsed;
|
|
70
179
|
}
|
|
71
180
|
this.log(`Querying ${this.recordLabel} records from org...`);
|
|
72
181
|
const result = await conn.query(this.soql);
|
|
@@ -90,13 +199,71 @@ export class InsuranceRuleConvertCommand extends SfCommand {
|
|
|
90
199
|
return parsed;
|
|
91
200
|
}
|
|
92
201
|
async resolveProductCodes(conn, ruleDefs) {
|
|
93
|
-
|
|
202
|
+
// Collect EVERY ProductPath segment, not just the root: merge mode needs the code of each
|
|
203
|
+
// segment to build the platform-compatible pathed rule key, and the leaf segment's code to
|
|
204
|
+
// resolve its CML type. The non-merge path only reads the root code, so this is a superset.
|
|
205
|
+
const productIds = collectAllProductIds(ruleDefs);
|
|
206
|
+
const productIdToName = new Map();
|
|
94
207
|
try {
|
|
95
|
-
|
|
208
|
+
const productIdToCode = await fetchProductCodes(conn, productIds, {
|
|
209
|
+
// M2: a blank ProductCode forces a Name/Id fallback, so the pathed rule key is derived from a
|
|
210
|
+
// non-authoritative field and will NOT match the platform-generated RuleKey — the surcharge
|
|
211
|
+
// then imports cleanly but silently never fires. Surface it instead of substituting silently.
|
|
212
|
+
onFallback: (productId) => this.warn(`Product ${productId} has no ProductCode; rule key derived from Name/Id and may not match the platform-generated RuleKey (surcharge may silently not fire)`),
|
|
213
|
+
// Capture Names so convert can emit them as the Type association reference value — the field
|
|
214
|
+
// the common importer resolves the Product2 by. Validated below before they reach the model.
|
|
215
|
+
collectNames: productIdToName,
|
|
216
|
+
});
|
|
217
|
+
// [Fix #8] An id we ASKED Product2 about and got nothing back for is distinct from a found
|
|
218
|
+
// product with a null ProductCode (which `onFallback` already covers). Missing-from-result
|
|
219
|
+
// ids mean the Product2 row is invalid / deleted / outside the visible scope — generation
|
|
220
|
+
// will silently fall back to the raw Id for that path segment, again yielding a non-matching
|
|
221
|
+
// platform RuleKey. Surface this case explicitly so the operator can investigate.
|
|
222
|
+
for (const id of productIds) {
|
|
223
|
+
if (!productIdToCode.has(id)) {
|
|
224
|
+
this.warn(`Product ${id} was not returned by Product2 query (not found, not visible, or filtered out); ` +
|
|
225
|
+
'rule key for paths through this product will fall back to the raw Id and may not match the platform-generated RuleKey');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
this.validateAssociationNames(productIdToName);
|
|
229
|
+
return { productIdToCode, productIdToName };
|
|
96
230
|
}
|
|
97
231
|
catch (e) {
|
|
98
232
|
this.warn(`Could not fetch product codes: ${e.message}. Using product IDs instead.`);
|
|
99
|
-
return new Map();
|
|
233
|
+
return { productIdToCode: new Map(), productIdToName: new Map() };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Validates the Id -> Name map that feeds each Type association's reference value, mutating it in
|
|
238
|
+
* place so only safe, importer-resolvable Names survive. The Name is written into the naive
|
|
239
|
+
* comma-joined associations CSV and, downstream, into the common importer's single-quoted SOQL
|
|
240
|
+
* `WHERE Name IN ('<Name>')`. Two hazards, neither of which we can fix in the (Rev-Cloud-owned)
|
|
241
|
+
* importer. Unsafe characters (comma, quote, backslash, newline) corrupt the CSV column or break
|
|
242
|
+
* out of the SOQL literal — such a Name is dropped from the map (the generator falls back to the
|
|
243
|
+
* ProductCode) and warned, so the association may not resolve but the output stays valid and
|
|
244
|
+
* injection-free instead of silently wrong. Duplicate Names across distinct product ids make the
|
|
245
|
+
* importer's by-Name lookup ambiguous (last-writer-wins), so a Type could bind to the wrong
|
|
246
|
+
* Product2 — we warn but keep the entries; the documented precondition is that Product Name is
|
|
247
|
+
* unique per migration scope.
|
|
248
|
+
*/
|
|
249
|
+
validateAssociationNames(productIdToName) {
|
|
250
|
+
const nameToIds = new Map();
|
|
251
|
+
for (const [productId, name] of productIdToName) {
|
|
252
|
+
if (!isSafeAssociationReferenceValue(name)) {
|
|
253
|
+
this.warn(`Product ${productId} Name "${name}" contains characters unsafe for the associations CSV / import SOQL; ` +
|
|
254
|
+
'falling back to ProductCode for its Type association (the association may not resolve on import)');
|
|
255
|
+
productIdToName.delete(productId);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const ids = nameToIds.get(name) ?? [];
|
|
259
|
+
ids.push(productId);
|
|
260
|
+
nameToIds.set(name, ids);
|
|
261
|
+
}
|
|
262
|
+
for (const [name, ids] of nameToIds) {
|
|
263
|
+
if (ids.length > 1) {
|
|
264
|
+
this.warn(`Product Name "${name}" is shared by ${ids.length} products (${ids.join(', ')}); ` +
|
|
265
|
+
'the import resolves Type associations by Name, so bindings may be ambiguous. Product Name must be unique.');
|
|
266
|
+
}
|
|
100
267
|
}
|
|
101
268
|
}
|
|
102
269
|
async discoverCmlApi(conn, ruleDefs, productIdToCode) {
|
|
@@ -111,33 +278,57 @@ export class InsuranceRuleConvertCommand extends SfCommand {
|
|
|
111
278
|
catch (e) {
|
|
112
279
|
this.warn(`CML auto-discovery failed: ${e.message}`);
|
|
113
280
|
}
|
|
114
|
-
|
|
281
|
+
// [Fix #5] The fallback API name is downstream written to disk as `<safeApi>.cml` and used in
|
|
282
|
+
// SOQL/log lines. Raw ProductCodes can contain spaces, slashes, quotes, or other characters
|
|
283
|
+
// that break path/SOQL semantics; sanitize each segment to the same `[A-Za-z0-9_]` alphabet
|
|
284
|
+
// the rest of the generator uses so the generated name is injection-/path-traversal-safe.
|
|
285
|
+
const codes = Array.from(productIds).map((id) => sanitizeName(productIdToCode.get(id) ?? id));
|
|
115
286
|
const generated = `${this.apiNamePrefix}${codes.join('_')}`;
|
|
116
287
|
this.log(`No existing CML found. Generated new CML API name: ${generated}`);
|
|
117
288
|
return generated;
|
|
118
289
|
}
|
|
119
|
-
async writeOutputFiles(cmlModel, ruleKeyMapping, safeApi, workspaceDir, api) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
290
|
+
async writeOutputFiles(cmlModel, ruleKeyMapping, safeApi, workspaceDir, api, recordUpdateFile) {
|
|
291
|
+
// [Fix #15] path.join for cross-platform path separators (was hardcoded '/'). See companion site
|
|
292
|
+
// in writeMergedOutputFiles — same rationale: Windows-unit-tests assert against path.join, and
|
|
293
|
+
// forward-slash literals broke the equality there.
|
|
294
|
+
const cmlPath = path.join(workspaceDir, `${safeApi}.cml`);
|
|
295
|
+
const associationsPath = path.join(workspaceDir, `${safeApi}_Associations.csv`);
|
|
296
|
+
const mappingPath = path.join(workspaceDir, `${safeApi}_RuleKeyMapping.json`);
|
|
123
297
|
await fs.writeFile(cmlPath, cmlModel.generateCml(), 'utf8');
|
|
124
298
|
await fs.writeFile(associationsPath, generateCsvForAssociations(safeApi, cmlModel.associations), 'utf8');
|
|
125
299
|
await fs.writeFile(mappingPath, JSON.stringify(ruleKeyMapping, null, 2), 'utf8');
|
|
126
300
|
this.log(`\nCML written to: ${cmlPath}`);
|
|
127
301
|
this.log(`Associations written to: ${associationsPath}`);
|
|
128
302
|
this.log(`Rule key mapping written to: ${mappingPath}`);
|
|
303
|
+
this.log(`Record update file written to: ${recordUpdateFile}`);
|
|
129
304
|
this.log(`\nConverted ${ruleKeyMapping.length} ${this.recordLabel} rules to CML`);
|
|
130
|
-
this.log('\nNext steps:');
|
|
131
|
-
this.log(' 1. Review the generated .cml file');
|
|
132
|
-
this.log(` 2.
|
|
133
|
-
this.log(
|
|
134
|
-
return { cmlFile: cmlPath, associationsFile: associationsPath, ruleKeyMapping };
|
|
305
|
+
this.log('\nNext steps (this command wrote nothing to the org):');
|
|
306
|
+
this.log(' 1. Review the generated .cml file and the record update file');
|
|
307
|
+
this.log(` 2. Activate the CML: sf cml import as-expression-set --cml-api ${api} --context-definition <CD_NAME> --target-org <org>`);
|
|
308
|
+
this.log(` 3. Apply the org-record changes enumerated in ${recordUpdateFile} to the target org`);
|
|
309
|
+
return { cmlFile: cmlPath, associationsFile: associationsPath, ruleKeyMapping, recordUpdateFile };
|
|
135
310
|
}
|
|
136
311
|
}
|
|
312
|
+
function collectAllProductIds(ruleDefs) {
|
|
313
|
+
const productIds = new Set();
|
|
314
|
+
for (const { record } of ruleDefs) {
|
|
315
|
+
// [Fix #11] One canonical split helper so trim + drop-empty semantics never diverge from the
|
|
316
|
+
// merge module's parsing.
|
|
317
|
+
for (const id of splitProductPath(record.ProductPath))
|
|
318
|
+
productIds.add(id);
|
|
319
|
+
}
|
|
320
|
+
return productIds;
|
|
321
|
+
}
|
|
322
|
+
// CML auto-discovery and the generated API name key off the ROOT product of each path only, so
|
|
323
|
+
// this stays a root-only collector (the merge path uses collectAllProductIds for the full set).
|
|
137
324
|
function collectRootProductIds(ruleDefs) {
|
|
138
325
|
const productIds = new Set();
|
|
139
326
|
for (const { record } of ruleDefs) {
|
|
140
|
-
|
|
327
|
+
// [Fix #11] splitProductPath already trims and drops empty segments, so the root is the first
|
|
328
|
+
// emitted id (or undefined when the entire path is blank).
|
|
329
|
+
const root = splitProductPath(record.ProductPath)[0];
|
|
330
|
+
if (root)
|
|
331
|
+
productIds.add(root);
|
|
141
332
|
}
|
|
142
333
|
return productIds;
|
|
143
334
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insurance-rule-convert-command.js","sourceRoot":"","sources":["../../../src/shared/insurance/insurance-rule-convert-command.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"insurance-rule-convert-command.js","sourceRoot":"","sources":["../../../src/shared/insurance/insurance-rule-convert-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,18 @@ export declare function sanitizeName(name: string): string;
|
|
|
9
9
|
export declare function decodeHtmlEntities(value: string): string;
|
|
10
10
|
export declare function buildStageTransition(ruleGroup?: UnderwritingRuleGroup): string | undefined;
|
|
11
11
|
export declare function generateRuleKey(prefix: string, productCode: string, apiName: string, stageTransition?: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Whether a product Name is safe to emit as a Type association's reference value
|
|
14
|
+
* (`$Product2ReferenceId`). That value travels two unescaped hops we do NOT own and cannot change:
|
|
15
|
+
* the naive comma-joined `_Associations.csv` column (a comma shifts every later column), and the
|
|
16
|
+
* common `cml import as-expression-set` resolver's single-quoted SOQL `WHERE Name IN ('<value>')`
|
|
17
|
+
* (a single quote breaks out of the literal; a backslash or newline corrupts the row).
|
|
18
|
+
* A Name failing this guard is dropped by the convert layer (it falls back to the ProductCode and
|
|
19
|
+
* warns) rather than silently producing a corrupt CSV / injecting SOQL. An empty / whitespace-only
|
|
20
|
+
* Name is also rejected — it can never match a real Product2 by name. Mirrors the reject-don't-escape
|
|
21
|
+
* stance of {@link isSafeQuotableString} for condition values.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isSafeAssociationReferenceValue(value: string): boolean;
|
|
12
24
|
export declare function buildConstraintDeclaration(ruleDef: {
|
|
13
25
|
ruleCriteria?: RuleCriteria[];
|
|
14
26
|
}): string;
|
|
@@ -17,10 +29,35 @@ export declare function collectAttributes(ruleDefs: Array<{
|
|
|
17
29
|
ruleCriteria?: RuleCriteria[];
|
|
18
30
|
};
|
|
19
31
|
}>): Set<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Collects only the attributes that actually reach the emitted CML — i.e. those on conditions whose
|
|
34
|
+
* `buildConditionExpression` returned a non-null expression. Conditions dropped by the safe-literal
|
|
35
|
+
* guard, an unknown operator, or missing values do NOT contribute their attribute. This is the
|
|
36
|
+
* companion to `collectAttributes` for merge-mode attribute-presence warnings: warning about an
|
|
37
|
+
* attribute the declaration never emitted (because the guard dropped its condition) is spurious
|
|
38
|
+
* noise on exactly the inputs the guard sanitized. Unlike `collectAttributes`, names are returned
|
|
39
|
+
* sanitized to match how they appear in the emitted declaration.
|
|
40
|
+
*/
|
|
41
|
+
export declare function collectEmittedAttributes(ruleDefs: Array<{
|
|
42
|
+
ruleDef: {
|
|
43
|
+
ruleCriteria?: RuleCriteria[];
|
|
44
|
+
};
|
|
45
|
+
}>): Set<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Derives the real CML data type for each collected attribute from its condition `dataType`.
|
|
48
|
+
* When an attribute appears with more than one distinct CML type (a conflict), or its type is
|
|
49
|
+
* unknown, it falls back to STRING. Returned alongside (not replacing) the Set from
|
|
50
|
+
* collectAttributes, which merge mode still depends on.
|
|
51
|
+
*/
|
|
52
|
+
export declare function collectAttributeTypes(ruleDefs: Array<{
|
|
53
|
+
ruleDef: {
|
|
54
|
+
ruleCriteria?: RuleCriteria[];
|
|
55
|
+
};
|
|
56
|
+
}>): Map<string, string>;
|
|
20
57
|
export declare function buildCmlModel(ruleDefs: Array<{
|
|
21
58
|
record: RuleRecord;
|
|
22
59
|
ruleDef: ParsedRuleDefinition;
|
|
23
|
-
}>, productIdToCode: Map<string, string>, keyPrefix: string, constraintLabel: string): {
|
|
60
|
+
}>, productIdToCode: Map<string, string>, keyPrefix: string, constraintLabel: string, ruleType?: string, productIdToName?: Map<string, string>): {
|
|
24
61
|
cmlModel: CmlModel;
|
|
25
62
|
ruleKeyMapping: RuleKeyEntry[];
|
|
26
63
|
};
|