@memberjunction/record-cloning-base 0.0.0 → 6.2.0-edge.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/LICENSE +183 -0
- package/README.md +28 -43
- package/dist/CloneConfigValidator.d.ts +109 -0
- package/dist/CloneConfigValidator.d.ts.map +1 -0
- package/dist/CloneConfigValidator.js +348 -0
- package/dist/CloneConfigValidator.js.map +1 -0
- package/dist/CloneFieldMapper.d.ts +103 -0
- package/dist/CloneFieldMapper.d.ts.map +1 -0
- package/dist/CloneFieldMapper.js +369 -0
- package/dist/CloneFieldMapper.js.map +1 -0
- package/dist/ClonePlanHash.d.ts +27 -0
- package/dist/ClonePlanHash.d.ts.map +1 -0
- package/dist/ClonePlanHash.js +130 -0
- package/dist/ClonePlanHash.js.map +1 -0
- package/dist/ClonePolicyResolver.d.ts +100 -0
- package/dist/ClonePolicyResolver.d.ts.map +1 -0
- package/dist/ClonePolicyResolver.js +247 -0
- package/dist/ClonePolicyResolver.js.map +1 -0
- package/dist/EffectiveOptions.d.ts +78 -0
- package/dist/EffectiveOptions.d.ts.map +1 -0
- package/dist/EffectiveOptions.js +156 -0
- package/dist/EffectiveOptions.js.map +1 -0
- package/dist/ExclusionClasses.d.ts +27 -0
- package/dist/ExclusionClasses.d.ts.map +1 -0
- package/dist/ExclusionClasses.js +81 -0
- package/dist/ExclusionClasses.js.map +1 -0
- package/dist/FieldMeta.d.ts +15 -0
- package/dist/FieldMeta.d.ts.map +1 -0
- package/dist/FieldMeta.js +41 -0
- package/dist/FieldMeta.js.map +1 -0
- package/dist/JsonRemapEngine.d.ts +42 -0
- package/dist/JsonRemapEngine.d.ts.map +1 -0
- package/dist/JsonRemapEngine.js +251 -0
- package/dist/JsonRemapEngine.js.map +1 -0
- package/dist/NameTemplate.d.ts +56 -0
- package/dist/NameTemplate.d.ts.map +1 -0
- package/dist/NameTemplate.js +193 -0
- package/dist/NameTemplate.js.map +1 -0
- package/dist/RowExclusion.d.ts +9 -0
- package/dist/RowExclusion.d.ts.map +1 -0
- package/dist/RowExclusion.js +19 -0
- package/dist/RowExclusion.js.map +1 -0
- package/dist/SensitiveValues.d.ts +12 -0
- package/dist/SensitiveValues.d.ts.map +1 -0
- package/dist/SensitiveValues.js +25 -0
- package/dist/SensitiveValues.js.map +1 -0
- package/dist/UniqueKeyClassifier.d.ts +52 -0
- package/dist/UniqueKeyClassifier.d.ts.map +1 -0
- package/dist/UniqueKeyClassifier.js +161 -0
- package/dist/UniqueKeyClassifier.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +260 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +31 -0
- package/dist/types.js.map +1 -0
- package/package.json +31 -8
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file CloneConfigValidator.ts
|
|
3
|
+
* Pure validation engine for IEntityCloneConfiguration bags.
|
|
4
|
+
* Enforces metadata referential integrity, field existence, writability,
|
|
5
|
+
* relationship resolution, and strict-mode drift guard.
|
|
6
|
+
* @see plans/record-cloning/README.md §4.5, §13.3
|
|
7
|
+
*/
|
|
8
|
+
import { IsRenameField } from './CloneFieldMapper.js';
|
|
9
|
+
const VALID_POLICIES = new Set(['Deep', 'Reference', 'Skip']);
|
|
10
|
+
export class CloneConfigValidator {
|
|
11
|
+
/**
|
|
12
|
+
* Validates an entity's clone configuration bag against its metadata.
|
|
13
|
+
*/
|
|
14
|
+
static Validate(entity, allEntities) {
|
|
15
|
+
const errors = [];
|
|
16
|
+
const config = entity.CloneConfiguration;
|
|
17
|
+
if (!config || config.Enabled === false) {
|
|
18
|
+
return errors;
|
|
19
|
+
}
|
|
20
|
+
const entityFields = new Map(entity.Fields.map((f) => [f.Name.toLowerCase(), f]));
|
|
21
|
+
// 1. Validate Caps
|
|
22
|
+
for (const cap of ['MaxDepth', 'MaxRecords']) {
|
|
23
|
+
const value = config[cap];
|
|
24
|
+
if (value !== undefined && (!Number.isInteger(value) || value <= 0)) {
|
|
25
|
+
errors.push({
|
|
26
|
+
EntityName: entity.Name,
|
|
27
|
+
PropertyPath: cap,
|
|
28
|
+
Message: `${cap} must be a positive integer, received: ${String(value)}`,
|
|
29
|
+
Severity: 'Error',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// 1b. Policies: Relationships, Descendants and preset overrides use Deep, Reference or Skip.
|
|
34
|
+
const checkPolicy = (policy, path) => {
|
|
35
|
+
if (policy !== undefined && !VALID_POLICIES.has(String(policy))) {
|
|
36
|
+
errors.push({
|
|
37
|
+
EntityName: entity.Name,
|
|
38
|
+
PropertyPath: path,
|
|
39
|
+
Message: `Policy must be Deep, Reference or Skip, received: ${String(policy)}`,
|
|
40
|
+
Severity: 'Error',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
for (const [key, rel] of Object.entries(config.Relationships ?? {}))
|
|
45
|
+
checkPolicy(rel?.Policy, `Relationships[${key}].Policy`);
|
|
46
|
+
for (const [key, desc] of Object.entries(config.Descendants ?? {}))
|
|
47
|
+
checkPolicy(desc?.Policy, `Descendants[${key}].Policy`);
|
|
48
|
+
for (const preset of config.Presets ?? []) {
|
|
49
|
+
for (const [key, rel] of Object.entries(preset?.Relationships ?? {}))
|
|
50
|
+
checkPolicy(rel?.Policy, `Presets[${preset.Key}].Relationships[${key}].Policy`);
|
|
51
|
+
}
|
|
52
|
+
// 2. Validate Fields section
|
|
53
|
+
const fieldsConfig = config.Fields;
|
|
54
|
+
if (fieldsConfig) {
|
|
55
|
+
const checkFieldExists = (fieldName, path) => {
|
|
56
|
+
if (!entityFields.has(fieldName.toLowerCase())) {
|
|
57
|
+
errors.push({
|
|
58
|
+
EntityName: entity.Name,
|
|
59
|
+
PropertyPath: path,
|
|
60
|
+
Message: `Field '${fieldName}' does not exist on entity '${entity.Name}'.`,
|
|
61
|
+
Severity: 'Error',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const checkWritable = (fieldName, path) => {
|
|
66
|
+
const f = entityFields.get(fieldName.toLowerCase());
|
|
67
|
+
if (f && f.IsSPParameter && f.IsSPParameter(false) === false) {
|
|
68
|
+
errors.push({
|
|
69
|
+
EntityName: entity.Name,
|
|
70
|
+
PropertyPath: path,
|
|
71
|
+
Message: `Field '${fieldName}' is computed or not writable on insert, cannot be used in ${path}.`,
|
|
72
|
+
Severity: 'Error',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
// Check Exclude
|
|
77
|
+
for (const f of fieldsConfig.Exclude || []) {
|
|
78
|
+
checkFieldExists(f, `Fields.Exclude[${f}]`);
|
|
79
|
+
}
|
|
80
|
+
// Check Reset
|
|
81
|
+
for (const f of Object.keys(fieldsConfig.Reset || {})) {
|
|
82
|
+
checkFieldExists(f, `Fields.Reset[${f}]`);
|
|
83
|
+
}
|
|
84
|
+
// Check Ownership
|
|
85
|
+
for (const f of fieldsConfig.Ownership || []) {
|
|
86
|
+
checkFieldExists(f, `Fields.Ownership[${f}]`);
|
|
87
|
+
}
|
|
88
|
+
// Check ServerAllocated (must exist and be writable on insert)
|
|
89
|
+
for (const f of fieldsConfig.ServerAllocated || []) {
|
|
90
|
+
checkFieldExists(f, `Fields.ServerAllocated[${f}]`);
|
|
91
|
+
checkWritable(f, `Fields.ServerAllocated[${f}]`);
|
|
92
|
+
}
|
|
93
|
+
// Check PromptFor (must exist and be writable on insert)
|
|
94
|
+
for (const f of fieldsConfig.PromptFor || []) {
|
|
95
|
+
checkFieldExists(f, `Fields.PromptFor[${f}]`);
|
|
96
|
+
checkWritable(f, `Fields.PromptFor[${f}]`);
|
|
97
|
+
}
|
|
98
|
+
// Check ClearTogether groups
|
|
99
|
+
for (const group of fieldsConfig.ClearTogether || []) {
|
|
100
|
+
for (const f of group) {
|
|
101
|
+
checkFieldExists(f, `Fields.ClearTogether[${f}]`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Check JsonRemap columns (must exist and be string type)
|
|
105
|
+
for (const remap of fieldsConfig.JsonRemap || []) {
|
|
106
|
+
if (!remap?.Field) {
|
|
107
|
+
errors.push({
|
|
108
|
+
EntityName: entity.Name,
|
|
109
|
+
PropertyPath: 'Fields.JsonRemap',
|
|
110
|
+
Message: 'Each JsonRemap entry needs a Field naming the JSON column.',
|
|
111
|
+
Severity: 'Error',
|
|
112
|
+
});
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
checkFieldExists(remap.Field, `Fields.JsonRemap[${remap.Field}]`);
|
|
116
|
+
if (!remap.Preset && !(remap.Rules?.length)) {
|
|
117
|
+
errors.push({
|
|
118
|
+
EntityName: entity.Name,
|
|
119
|
+
PropertyPath: `Fields.JsonRemap[${remap.Field}]`,
|
|
120
|
+
Message: `JsonRemap for '${remap.Field}' has neither Rules nor a Preset, so it would rewrite nothing.`,
|
|
121
|
+
Severity: 'Error',
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
for (const rule of remap.Rules ?? []) {
|
|
125
|
+
if (!rule?.Path || !rule?.Mode) {
|
|
126
|
+
errors.push({
|
|
127
|
+
EntityName: entity.Name,
|
|
128
|
+
PropertyPath: `Fields.JsonRemap[${remap.Field}].Rules`,
|
|
129
|
+
Message: `Each JsonRemap rule for '${remap.Field}' needs a Path and a Mode.`,
|
|
130
|
+
Severity: 'Error',
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const f = entityFields.get(remap.Field.toLowerCase());
|
|
135
|
+
if (f && f.Type && !f.Type.toLowerCase().includes('varchar') && !f.Type.toLowerCase().includes('text') && !f.Type.toLowerCase().includes('json')) {
|
|
136
|
+
errors.push({
|
|
137
|
+
EntityName: entity.Name,
|
|
138
|
+
PropertyPath: `Fields.JsonRemap[${remap.Field}]`,
|
|
139
|
+
Message: `Field '${remap.Field}' is of type '${f.Type}', but JsonRemap requires a string or JSON column.`,
|
|
140
|
+
Severity: 'Error',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Strict-Mode Drift Guard (§13.3)
|
|
145
|
+
if (fieldsConfig.Strict) {
|
|
146
|
+
const classifiedFields = new Set();
|
|
147
|
+
for (const f of fieldsConfig.Copy || [])
|
|
148
|
+
classifiedFields.add(f.toLowerCase());
|
|
149
|
+
for (const f of fieldsConfig.Exclude || [])
|
|
150
|
+
classifiedFields.add(f.toLowerCase());
|
|
151
|
+
for (const f of Object.keys(fieldsConfig.Reset || {}))
|
|
152
|
+
classifiedFields.add(f.toLowerCase());
|
|
153
|
+
for (const f of fieldsConfig.Ownership || [])
|
|
154
|
+
classifiedFields.add(f.toLowerCase());
|
|
155
|
+
for (const f of fieldsConfig.ServerAllocated || [])
|
|
156
|
+
classifiedFields.add(f.toLowerCase());
|
|
157
|
+
for (const f of fieldsConfig.PromptFor || [])
|
|
158
|
+
classifiedFields.add(f.toLowerCase());
|
|
159
|
+
for (const remap of fieldsConfig.JsonRemap || [])
|
|
160
|
+
if (remap?.Field)
|
|
161
|
+
classifiedFields.add(remap.Field.toLowerCase());
|
|
162
|
+
for (const rule of fieldsConfig.Rules?.Rules || []) {
|
|
163
|
+
const target = rule.TargetField || rule.Field;
|
|
164
|
+
if (target)
|
|
165
|
+
classifiedFields.add(target.toLowerCase());
|
|
166
|
+
}
|
|
167
|
+
const unclassified = [];
|
|
168
|
+
for (const field of entity.Fields) {
|
|
169
|
+
if (field.IsPrimaryKey ||
|
|
170
|
+
field.IsCreatedAtField ||
|
|
171
|
+
field.IsUpdatedAtField ||
|
|
172
|
+
field.IsSoftDeleteField ||
|
|
173
|
+
(field.IsSPParameter && field.IsSPParameter(false) === false)) {
|
|
174
|
+
continue; // Automatically classified
|
|
175
|
+
}
|
|
176
|
+
if (!classifiedFields.has(field.Name.toLowerCase())) {
|
|
177
|
+
unclassified.push(field.Name);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (unclassified.length > 0) {
|
|
181
|
+
errors.push({
|
|
182
|
+
EntityName: entity.Name,
|
|
183
|
+
PropertyPath: 'Fields.Strict',
|
|
184
|
+
Message: `Strict mode enabled: unclassified fields detected on entity '${entity.Name}': [${unclassified.join(', ')}]. Every field must be classified in Copy, Exclude, Reset, Ownership, ServerAllocated, PromptFor, or JsonRemap.`,
|
|
185
|
+
Severity: 'Error',
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// 3. Validate Relationships section
|
|
191
|
+
if (config.Relationships) {
|
|
192
|
+
// Keys may name a relationship (ID or Name), its related entity, "<Entity>.<JoinField>",
|
|
193
|
+
// or an entity this one references through a foreign key.
|
|
194
|
+
const relMap = new Set();
|
|
195
|
+
for (const r of entity.Relationships || []) {
|
|
196
|
+
if (r.ID)
|
|
197
|
+
relMap.add(r.ID.toLowerCase());
|
|
198
|
+
if (r.Name)
|
|
199
|
+
relMap.add(r.Name.toLowerCase());
|
|
200
|
+
if (r.RelatedEntity)
|
|
201
|
+
relMap.add(r.RelatedEntity.toLowerCase());
|
|
202
|
+
if (r.RelatedEntity && r.RelatedEntityJoinField)
|
|
203
|
+
relMap.add(`${r.RelatedEntity}.${r.RelatedEntityJoinField}`.toLowerCase());
|
|
204
|
+
}
|
|
205
|
+
for (const f of entity.Fields) {
|
|
206
|
+
if (f.RelatedEntity)
|
|
207
|
+
relMap.add(f.RelatedEntity.toLowerCase());
|
|
208
|
+
}
|
|
209
|
+
const knownEntities = allEntities ? new Set(allEntities.map((e) => e.Name.toLowerCase())) : null;
|
|
210
|
+
for (const relKey of Object.keys(config.Relationships)) {
|
|
211
|
+
if (relMap.has(relKey.toLowerCase()))
|
|
212
|
+
continue;
|
|
213
|
+
const entityPart = relKey.includes('.') && knownEntities && !knownEntities.has(relKey.toLowerCase()) ? relKey.slice(0, relKey.lastIndexOf('.')) : relKey;
|
|
214
|
+
const exists = knownEntities?.has(entityPart.toLowerCase());
|
|
215
|
+
// A qualified key also applies to rows further down the graph, so an entity that exists
|
|
216
|
+
// may still be reached through a descendant. A bare entity name applies only to the
|
|
217
|
+
// root's own relationships, so one that isn't among them matches nothing.
|
|
218
|
+
const qualified = entityPart !== relKey;
|
|
219
|
+
errors.push({
|
|
220
|
+
EntityName: entity.Name,
|
|
221
|
+
PropertyPath: `Relationships[${relKey}]`,
|
|
222
|
+
Message: !exists
|
|
223
|
+
? `Relationship key '${relKey}' does not match any known relationship or related entity on '${entity.Name}'.`
|
|
224
|
+
: qualified
|
|
225
|
+
? `'${relKey}' is not a direct relationship of '${entity.Name}'; it applies only where the clone reaches it through a descendant.`
|
|
226
|
+
: `'${relKey}' is not a relationship of '${entity.Name}', and a bare entity name applies only to the root's own relationships. Name the join column ('${relKey}.<JoinField>') for rows reached through a descendant.`,
|
|
227
|
+
Severity: exists && qualified ? 'Warning' : 'Error',
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// 4. Validate ServerGeneratedChildren
|
|
232
|
+
if (config.Hooks?.ServerGeneratedChildren && allEntities) {
|
|
233
|
+
const allEntityNames = new Set(allEntities.map((e) => e.Name.toLowerCase()));
|
|
234
|
+
for (const childEntity of config.Hooks.ServerGeneratedChildren) {
|
|
235
|
+
if (!allEntityNames.has(childEntity.toLowerCase())) {
|
|
236
|
+
errors.push({
|
|
237
|
+
EntityName: entity.Name,
|
|
238
|
+
PropertyPath: `Hooks.ServerGeneratedChildren[${childEntity}]`,
|
|
239
|
+
Message: `ServerGeneratedChild entity '${childEntity}' is not recognized in entity metadata.`,
|
|
240
|
+
Severity: 'Error',
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
// 5. Validate Derivation.Field (must be self-FK)
|
|
246
|
+
if (config.Derivation?.Field) {
|
|
247
|
+
const derField = entityFields.get(config.Derivation.Field.toLowerCase());
|
|
248
|
+
if (!derField) {
|
|
249
|
+
errors.push({
|
|
250
|
+
EntityName: entity.Name,
|
|
251
|
+
PropertyPath: 'Derivation.Field',
|
|
252
|
+
Message: `Derivation field '${config.Derivation.Field}' does not exist on entity '${entity.Name}'.`,
|
|
253
|
+
Severity: 'Error',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
else if (derField.RelatedEntity?.toLowerCase() !== entity.Name.toLowerCase()) {
|
|
257
|
+
errors.push({
|
|
258
|
+
EntityName: entity.Name,
|
|
259
|
+
PropertyPath: 'Derivation.Field',
|
|
260
|
+
Message: `Derivation field '${config.Derivation.Field}' must be a self-FK pointing to '${entity.Name}', points to '${derField.RelatedEntity}'.`,
|
|
261
|
+
Severity: 'Error',
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
errors.push(...CloneConfigValidator.unhonoredKeys(entity.Name, config));
|
|
266
|
+
errors.push(...CloneConfigValidator.promptNaming(entity, config));
|
|
267
|
+
return errors;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* `Naming.Strategy: 'prompt'` leaves every rename field (the name field, each unique string) at
|
|
271
|
+
* the source's value for the user to replace, but only `PromptFor` fields make the plan wait for
|
|
272
|
+
* one. A rename field that is neither prompted nor set by a rule would copy verbatim and fail on
|
|
273
|
+
* its unique index at save.
|
|
274
|
+
*/
|
|
275
|
+
static promptNaming(entity, config) {
|
|
276
|
+
const found = [];
|
|
277
|
+
const naming = config.Naming;
|
|
278
|
+
if (naming?.Strategy === 'prompt') {
|
|
279
|
+
const covered = new Set([
|
|
280
|
+
...(config.Fields?.PromptFor ?? []),
|
|
281
|
+
...(config.Fields?.Rules?.Rules ?? []).map((r) => r.TargetField || r.Field || ''),
|
|
282
|
+
...Object.keys(config.Fields?.Reset ?? {}),
|
|
283
|
+
...(config.Fields?.Exclude ?? []),
|
|
284
|
+
...(config.Fields?.ServerAllocated ?? []),
|
|
285
|
+
].map((f) => f.toLowerCase()));
|
|
286
|
+
for (const field of entity.Fields.filter((f) => !f.IsPrimaryKey && IsRenameField(f))) {
|
|
287
|
+
if (covered.has(field.Name.toLowerCase()))
|
|
288
|
+
continue;
|
|
289
|
+
found.push({
|
|
290
|
+
EntityName: entity.Name,
|
|
291
|
+
PropertyPath: 'Naming.Strategy',
|
|
292
|
+
Message: `Naming.Strategy 'prompt' needs '${field.Name}' in Fields.PromptFor or set by a rule: otherwise the copy keeps the source's value.`,
|
|
293
|
+
Severity: 'Error',
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const descendants = config.Descendants ?? {};
|
|
298
|
+
for (const [name, desc] of Object.entries(descendants)) {
|
|
299
|
+
if (desc?.Fields?.PromptFor?.length) {
|
|
300
|
+
found.push({
|
|
301
|
+
EntityName: entity.Name,
|
|
302
|
+
PropertyPath: `Descendants[${name}].Fields.PromptFor`,
|
|
303
|
+
Message: `PromptFor under Descendants is not prompted: only the root's PromptFor fields are asked for.`,
|
|
304
|
+
Severity: 'Warning',
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return found;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Keys the configuration schema defines but this release of the engine does not act on. Each
|
|
312
|
+
* is a warning, so a config author does not rely on it silently.
|
|
313
|
+
*/
|
|
314
|
+
static unhonoredKeys(entityName, config) {
|
|
315
|
+
const raw = config;
|
|
316
|
+
const at = (value, key) => (value && typeof value === 'object' ? value[key] : undefined);
|
|
317
|
+
const found = [];
|
|
318
|
+
if (raw.CreationPath !== undefined)
|
|
319
|
+
found.push('CreationPath');
|
|
320
|
+
if (raw.Embeddings === 'regenerate')
|
|
321
|
+
found.push('Embeddings');
|
|
322
|
+
if (at(raw.Naming, 'Fields') !== undefined)
|
|
323
|
+
found.push('Naming.Fields');
|
|
324
|
+
for (const key of ['PreSaveOverrides', 'RestoreAfterSave', 'PostCloneAction']) {
|
|
325
|
+
if (at(raw.Hooks, key) !== undefined)
|
|
326
|
+
found.push(`Hooks.${key}`);
|
|
327
|
+
}
|
|
328
|
+
if (at(raw.Fields, 'ClearTogether') !== undefined)
|
|
329
|
+
found.push('Fields.ClearTogether');
|
|
330
|
+
const scanRelationships = (bag, path) => {
|
|
331
|
+
for (const [name, policy] of Object.entries(bag ?? {})) {
|
|
332
|
+
for (const key of ['PreserveSequence', 'IncludeWhen']) {
|
|
333
|
+
if (at(policy, key) !== undefined)
|
|
334
|
+
found.push(`${path}[${name}].${key}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
scanRelationships(raw.Relationships, 'Relationships');
|
|
339
|
+
(Array.isArray(raw.Presets) ? raw.Presets : []).forEach((preset, i) => scanRelationships(at(preset, 'Relationships'), `Presets[${String(at(preset, 'Key') ?? i)}].Relationships`));
|
|
340
|
+
return found.map((path) => ({
|
|
341
|
+
EntityName: entityName,
|
|
342
|
+
PropertyPath: path,
|
|
343
|
+
Message: `'${path}' is not honored in this release of record cloning; it has no effect.`,
|
|
344
|
+
Severity: 'Warning',
|
|
345
|
+
}));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=CloneConfigValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CloneConfigValidator.js","sourceRoot":"","sources":["../src/CloneConfigValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file CloneFieldMapper.ts
|
|
3
|
+
* Pure 13-stage field mapping pipeline for record cloning.
|
|
4
|
+
* Maps: Excluded -> NotWritable -> DeniedRead/DeniedCreate -> Copy -> Reset -> Ownership
|
|
5
|
+
* -> ServerAllocated -> Rename -> Remap -> RemapJSON -> Override -> Prompt -> Rule.
|
|
6
|
+
* Rules run last, so a derived field (a user's Name from the prompted Email) sees the final
|
|
7
|
+
* values; request overrides and prompts are refused on fields a rule or reset governs.
|
|
8
|
+
* @see plans/record-cloning/README.md §7.1, §7.2, §13.1
|
|
9
|
+
*/
|
|
10
|
+
import { CloneFieldChange } from './types.js';
|
|
11
|
+
import { NameTemplateOptions } from './NameTemplate.js';
|
|
12
|
+
import { JsonRemapRule } from './JsonRemapEngine.js';
|
|
13
|
+
export interface FieldMappingFieldMeta {
|
|
14
|
+
Name: string;
|
|
15
|
+
IsPrimaryKey: boolean;
|
|
16
|
+
IsIdentity?: boolean;
|
|
17
|
+
IsNameField?: boolean;
|
|
18
|
+
IsUnique?: boolean;
|
|
19
|
+
RelatedEntityID?: string | null;
|
|
20
|
+
RelatedEntity?: string | null;
|
|
21
|
+
RelatedEntityJoinField?: string | null;
|
|
22
|
+
EntityIDFieldName?: string | null;
|
|
23
|
+
Type?: string;
|
|
24
|
+
IsSPParameter?: (forUpdate: boolean) => boolean;
|
|
25
|
+
DefaultValue?: string | null;
|
|
26
|
+
AllowsNull?: boolean;
|
|
27
|
+
IsCreatedAtField?: boolean;
|
|
28
|
+
IsUpdatedAtField?: boolean;
|
|
29
|
+
IsSoftDeleteField?: boolean;
|
|
30
|
+
/** Stored encrypted. Its values are masked wherever a plan leaves the server. */
|
|
31
|
+
Encrypted?: boolean;
|
|
32
|
+
/** Column width in characters; 0 or unset means unlimited. */
|
|
33
|
+
MaxLength?: number;
|
|
34
|
+
}
|
|
35
|
+
/** Whether the mapper renames this field on a clone: the name field, a field called Name, or a unique nvarchar. */
|
|
36
|
+
export declare function IsRenameField(field: FieldMappingFieldMeta): boolean;
|
|
37
|
+
export interface CloneFieldMappingContext {
|
|
38
|
+
EntityName: string;
|
|
39
|
+
Fields: FieldMappingFieldMeta[];
|
|
40
|
+
SourceRecord: Record<string, unknown>;
|
|
41
|
+
CurrentUserId?: string;
|
|
42
|
+
KeyMap?: Record<string, string>;
|
|
43
|
+
NamingOptions?: NameTemplateOptions & {
|
|
44
|
+
ExistingNames?: Set<string>;
|
|
45
|
+
/** Values already in use, per field, so a rename avoids them. Takes precedence over `ExistingNames`. */
|
|
46
|
+
ExistingNamesByField?: Record<string, Set<string>>;
|
|
47
|
+
UserName?: string;
|
|
48
|
+
};
|
|
49
|
+
FieldRules?: {
|
|
50
|
+
Exclude?: string[];
|
|
51
|
+
Reset?: Record<string, unknown>;
|
|
52
|
+
Ownership?: string[];
|
|
53
|
+
ServerAllocated?: string[];
|
|
54
|
+
PromptFor?: string[];
|
|
55
|
+
JsonRemap?: Array<{
|
|
56
|
+
Field: string;
|
|
57
|
+
Rules?: JsonRemapRule[];
|
|
58
|
+
Preset?: 'dashboard-ui-config' | 'scheduled-job-configuration';
|
|
59
|
+
}>;
|
|
60
|
+
Rules?: {
|
|
61
|
+
Rules?: Array<{
|
|
62
|
+
TargetField?: string;
|
|
63
|
+
Field?: string;
|
|
64
|
+
Source?: {
|
|
65
|
+
Kind: string;
|
|
66
|
+
Field?: string;
|
|
67
|
+
Value?: unknown;
|
|
68
|
+
};
|
|
69
|
+
}>;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
FLS?: {
|
|
73
|
+
DeniedReadFields?: string[];
|
|
74
|
+
DeniedCreateFields?: string[];
|
|
75
|
+
};
|
|
76
|
+
/** Request-level field values. Applied only when `RequestFieldsEditable`, and never to a field the configuration governs. */
|
|
77
|
+
RequestOverrides?: Record<string, unknown>;
|
|
78
|
+
/** Values the user supplied for `FieldRules.PromptFor` fields. Other fields are ignored. */
|
|
79
|
+
PromptedValues?: Record<string, unknown>;
|
|
80
|
+
/** The entity's `UserEditable` allows field edits ('fields' or 'all'). Default true. */
|
|
81
|
+
RequestFieldsEditable?: boolean;
|
|
82
|
+
IsRoot?: boolean;
|
|
83
|
+
NewParentKey?: unknown;
|
|
84
|
+
HierarchyParentField?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface CloneFieldMappingResult {
|
|
87
|
+
FieldChanges: CloneFieldChange[];
|
|
88
|
+
MappedValues: Record<string, unknown>;
|
|
89
|
+
RequiresIdentitySecondPass: boolean;
|
|
90
|
+
/** Request values the mapper refused, with why; the planner reports each as a warning. */
|
|
91
|
+
IgnoredRequestValues: Array<{
|
|
92
|
+
Field: string;
|
|
93
|
+
Kind: 'Override' | 'Prompt';
|
|
94
|
+
Reason: string;
|
|
95
|
+
}>;
|
|
96
|
+
/** Rename fields for which no free name fits the column; the planner blocks on these. */
|
|
97
|
+
NamingFailures: string[];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Runs the deterministic 12-stage field transformation pipeline on a record.
|
|
101
|
+
*/
|
|
102
|
+
export declare function MapFieldsForClone(ctx: CloneFieldMappingContext): CloneFieldMappingResult;
|
|
103
|
+
//# sourceMappingURL=CloneFieldMapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CloneFieldMapper.d.ts","sourceRoot":"","sources":["../src/CloneFieldMapper.ts"],"names":[],"mappings":"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"}
|