@contrail/cli 3.5.0-alpha.dd20a19 → 3.5.1-alpha.68d57e0
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 +1 -33
- package/node_modules/@contrail/loader/lib/color-processor.js +9 -23
- package/node_modules/@contrail/loader/lib/color-processor.spec.js +112 -62
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.d.ts +1 -1
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.js +2 -0
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.spec.js +4 -0
- package/node_modules/@contrail/loader/lib/common/color-validation.d.ts +26 -0
- package/node_modules/@contrail/loader/lib/common/color-validation.js +163 -0
- package/node_modules/@contrail/loader/lib/common/color-validation.spec.js +102 -0
- package/node_modules/@contrail/loader/lib/common/size-range-helpers.js +0 -1
- package/node_modules/@contrail/loader/lib/constants.d.ts +0 -3
- package/node_modules/@contrail/loader/lib/constants.js +1 -4
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.js +9 -23
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.spec.js +112 -62
- package/node_modules/@contrail/loader/lib/entities-v2/entities-helper.js +0 -1
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/assortment-processor.js +0 -1
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.js +8 -22
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.spec.js +43 -1
- package/node_modules/@contrail/loader/lib/pipeline/identifier-resolver.d.ts +5 -0
- package/node_modules/@contrail/loader/lib/pipeline/identifier-resolver.js +562 -0
- package/node_modules/@contrail/loader/lib/pipeline/identifier-resolver.spec.js +231 -0
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.js +77 -3
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.spec.js +82 -0
- package/node_modules/@contrail/loader/lib/pipeline/preview.js +0 -5
- package/node_modules/@contrail/loader/lib/pipeline/preview.spec.js +2 -2
- package/node_modules/@contrail/loader/lib/pipeline/project-item-execute-helpers.js +1 -1
- package/node_modules/@contrail/loader/lib/pipeline/transform.js +18 -0
- package/node_modules/@contrail/loader/lib/pipeline/transform.spec.js +3 -2
- package/node_modules/@contrail/loader/lib/pipeline/types.d.ts +5 -2
- package/node_modules/@contrail/loader/lib/pipeline/types.js +2 -0
- package/node_modules/@contrail/loader/lib/pipeline/validate.js +184 -437
- package/node_modules/@contrail/loader/lib/pipeline/validate.spec.js +157 -53
- package/node_modules/@contrail/loader/package.json +3 -2
- package/node_modules/@contrail/sdk/.github/workflows/publish-to-npm.yml +120 -0
- package/node_modules/@contrail/sdk/lib/auth/login.js +42 -3
- package/node_modules/@contrail/sdk/lib/core/request.d.ts +3 -0
- package/node_modules/@contrail/sdk/lib/core/request.js +100 -4
- package/node_modules/@contrail/sdk/lib/entities/entities.client.js +1 -1
- package/node_modules/@contrail/sdk/lib/entities/entity.resource.registry.js +1 -0
- package/node_modules/@contrail/sdk/lib/files/files.d.ts +13 -3
- package/node_modules/@contrail/sdk/lib/files/files.js +66 -25
- package/node_modules/@contrail/sdk/package.json +4 -1
- package/node_modules/validate-color/LICENSE +21 -0
- package/node_modules/validate-color/README.md +265 -0
- package/node_modules/validate-color/lib/index.d.ts +10 -0
- package/node_modules/validate-color/lib/index.js +1 -0
- package/node_modules/validate-color/package.json +91 -0
- package/node_modules/validate-color/test/redos.js +29 -0
- package/oclif.manifest.json +1 -79
- package/package.json +3 -6
- package/dist/api/dash0/client.d.ts +0 -13
- package/dist/api/dash0/client.js +0 -53
- package/dist/api/dash0/spans.d.ts +0 -8
- package/dist/api/dash0/spans.js +0 -91
- package/dist/api/dash0/types.d.ts +0 -84
- package/dist/api/dash0/types.js +0 -4
- package/dist/commands/event-workflows/assess-impact.d.ts +0 -19
- package/dist/commands/event-workflows/assess-impact.js +0 -104
- package/dist/helpers/event-workflow-impact/aggregate.d.ts +0 -23
- package/dist/helpers/event-workflow-impact/aggregate.js +0 -49
- package/dist/helpers/event-workflow-impact/aggregate.spec.js +0 -109
- package/dist/helpers/event-workflow-impact/classify.d.ts +0 -13
- package/dist/helpers/event-workflow-impact/classify.js +0 -135
- package/dist/helpers/event-workflow-impact/classify.spec.js +0 -138
- package/dist/helpers/event-workflow-impact/render.d.ts +0 -12
- package/dist/helpers/event-workflow-impact/render.js +0 -62
- package/dist/helpers/event-workflow-impact/subtree.d.ts +0 -20
- package/dist/helpers/event-workflow-impact/subtree.js +0 -93
- package/dist/helpers/event-workflow-impact/subtree.spec.d.ts +0 -1
- package/dist/helpers/event-workflow-impact/subtree.spec.js +0 -103
- /package/{dist/helpers/event-workflow-impact/aggregate.spec.d.ts → node_modules/@contrail/loader/lib/common/color-validation.spec.d.ts} +0 -0
- /package/{dist/helpers/event-workflow-impact/classify.spec.d.ts → node_modules/@contrail/loader/lib/pipeline/identifier-resolver.spec.d.ts} +0 -0
|
@@ -2,15 +2,33 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validate = void 0;
|
|
4
4
|
const types_1 = require("@contrail/types");
|
|
5
|
+
const lodash_1 = require("lodash");
|
|
6
|
+
const data_transformer_functions_1 = require("../common/data-transformer-functions");
|
|
5
7
|
const entity_processor_v2_1 = require("../entities-v2/entity-processor-v2");
|
|
6
8
|
const processor_registry_1 = require("../processor-registry");
|
|
7
9
|
const entities_helper_1 = require("../entities-v2/entities-helper");
|
|
10
|
+
const entities_helper_2 = require("../common/entities-helper");
|
|
11
|
+
const chunk_by_url_length_1 = require("../common/chunk-by-url-length");
|
|
12
|
+
const pLimit = require('p-limit');
|
|
8
13
|
const types_2 = require("./types");
|
|
9
14
|
const CONFIG_CATEGORY = types_2.PreValidationCategory.CONFIG;
|
|
10
15
|
const MISSING_REQUIRED_FIELD_CATEGORY = types_2.PreValidationCategory.MISSING_REQUIRED_FIELD;
|
|
11
16
|
const REFERENCE_NOT_FOUND_CATEGORY = types_2.PreValidationCategory.REFERENCE_DATA_NOT_FOUND;
|
|
12
17
|
const FAMILY_INCONSISTENT_CATEGORY = types_2.PreValidationCategory.FAMILY_PROPERTY_VALUES_INCONSISTENT;
|
|
13
18
|
const SELF_REFERENCE_CATEGORY = types_2.PreValidationCategory.SELF_REFERENCE;
|
|
19
|
+
function issueTypeToCategory(issueType) {
|
|
20
|
+
switch (issueType) {
|
|
21
|
+
case types_2.IssueType.INVALID_DATA:
|
|
22
|
+
return types_2.PreValidationCategory.INVALID_DATA;
|
|
23
|
+
case types_2.IssueType.MISSING_DATA:
|
|
24
|
+
return types_2.PreValidationCategory.MISSING_REQUIRED_FIELD;
|
|
25
|
+
case types_2.IssueType.DUPLICATE_FEDERATED_ID:
|
|
26
|
+
return types_2.PreValidationCategory.DUPLICATE_FEDERATED_ID;
|
|
27
|
+
case types_2.IssueType.CONFIG:
|
|
28
|
+
default:
|
|
29
|
+
return types_2.PreValidationCategory.CONFIG;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
14
32
|
function isEmpty(value) {
|
|
15
33
|
return value === null || value === undefined || value === '';
|
|
16
34
|
}
|
|
@@ -26,24 +44,15 @@ async function validate(rows, config, columnAnalysis, client) {
|
|
|
26
44
|
if (!rows?.length) {
|
|
27
45
|
return buildResult(issues);
|
|
28
46
|
}
|
|
47
|
+
if (columnAnalysis.identifierIssues?.length) {
|
|
48
|
+
issues.push(...columnAnalysis.identifierIssues);
|
|
49
|
+
}
|
|
29
50
|
const processorIssues = runProcessorValidation(rows, config);
|
|
30
51
|
issues.push(...processorIssues);
|
|
31
52
|
const itemNameIssues = validateItemNames(rows, config);
|
|
32
53
|
issues.push(...itemNameIssues);
|
|
33
54
|
const identifierConflictIssues = validateStaticIdentifierConflicts(config);
|
|
34
55
|
issues.push(...identifierConflictIssues);
|
|
35
|
-
const projectItemColumnIssues = validateProjectItemColumns(rows, config);
|
|
36
|
-
issues.push(...projectItemColumnIssues);
|
|
37
|
-
if (client && projectItemColumnIssues.length === 0) {
|
|
38
|
-
const resolutionIssues = await validateAndResolveProjectIdentifiers(rows, config, client);
|
|
39
|
-
issues.push(...resolutionIssues);
|
|
40
|
-
}
|
|
41
|
-
const assortmentColumnIssues = validateAssortmentColumns(rows, config);
|
|
42
|
-
issues.push(...assortmentColumnIssues);
|
|
43
|
-
if (client && assortmentColumnIssues.length === 0) {
|
|
44
|
-
const assortmentIssues = await validateAndResolveAssortmentIdentifiers(rows, config, client);
|
|
45
|
-
issues.push(...assortmentIssues);
|
|
46
|
-
}
|
|
47
56
|
const partialUpdateIssues = validatePartialAssortmentConfig(rows, config);
|
|
48
57
|
issues.push(...partialUpdateIssues);
|
|
49
58
|
const typePathExistenceIssues = validateTypePathExistence(columnAnalysis.typesByPath);
|
|
@@ -54,6 +63,12 @@ async function validate(rows, config, columnAnalysis, client) {
|
|
|
54
63
|
issues.push(...suffixIssues);
|
|
55
64
|
const selfRefIssues = validateSelfReferences(rows, config, columnAnalysis.typesByPath);
|
|
56
65
|
issues.push(...selfRefIssues);
|
|
66
|
+
if (client) {
|
|
67
|
+
const objectRefIssues = await validateObjectReferences(rows, columnAnalysis.typesByPath, client);
|
|
68
|
+
issues.push(...objectRefIssues);
|
|
69
|
+
}
|
|
70
|
+
const transformIssues = promoteTransformValidationErrors(columnAnalysis);
|
|
71
|
+
issues.push(...transformIssues);
|
|
57
72
|
const optionSetIssues = validateOptionSets(rows, columnAnalysis.typePropertyMaps);
|
|
58
73
|
issues.push(...optionSetIssues);
|
|
59
74
|
const booleanIssues = validateBooleanFormats(rows, columnAnalysis.typePropertyMaps);
|
|
@@ -143,7 +158,7 @@ function runProcessorValidation(rows, config) {
|
|
|
143
158
|
for (const colIssue of error.columnIssues ?? []) {
|
|
144
159
|
issues.push({
|
|
145
160
|
severity: types_2.PreValidationSeverity.ERROR,
|
|
146
|
-
category:
|
|
161
|
+
category: issueTypeToCategory(colIssue.issueType),
|
|
147
162
|
columnName: colIssue.columnName,
|
|
148
163
|
propertySlug: colIssue.columnName,
|
|
149
164
|
propertyType: '',
|
|
@@ -156,7 +171,7 @@ function runProcessorValidation(rows, config) {
|
|
|
156
171
|
for (const colIssue of warning.columnIssues ?? []) {
|
|
157
172
|
issues.push({
|
|
158
173
|
severity: types_2.PreValidationSeverity.WARNING,
|
|
159
|
-
category:
|
|
174
|
+
category: issueTypeToCategory(colIssue.issueType),
|
|
160
175
|
columnName: colIssue.columnName,
|
|
161
176
|
propertySlug: colIssue.columnName,
|
|
162
177
|
propertyType: '',
|
|
@@ -167,48 +182,89 @@ function runProcessorValidation(rows, config) {
|
|
|
167
182
|
}
|
|
168
183
|
return issues;
|
|
169
184
|
}
|
|
185
|
+
function promoteTransformValidationErrors(columnAnalysis) {
|
|
186
|
+
const issues = [];
|
|
187
|
+
const buckets = [
|
|
188
|
+
...(columnAnalysis.errors ?? []),
|
|
189
|
+
...(columnAnalysis.warnings ?? []),
|
|
190
|
+
];
|
|
191
|
+
const optionSetMap = columnAnalysis.typePropertyMaps?.optionSetUsingTypePropertiesBySlug ?? {};
|
|
192
|
+
const isOptionSetColumn = (col) => Boolean(optionSetMap[col] || optionSetMap[(0, data_transformer_functions_1.removeOptionOrFamilySuffix)(col)]);
|
|
193
|
+
const grouped = new Map();
|
|
194
|
+
for (const issue of buckets) {
|
|
195
|
+
for (const ci of issue?.columnIssues ?? []) {
|
|
196
|
+
if (ci?.issueType !== types_2.IssueType.VALIDATION_ERROR)
|
|
197
|
+
continue;
|
|
198
|
+
if (isOptionSetColumn(ci.columnName))
|
|
199
|
+
continue;
|
|
200
|
+
const key = `${ci.columnName}::${ci.message}`;
|
|
201
|
+
if (!grouped.has(key)) {
|
|
202
|
+
grouped.set(key, { columnName: ci.columnName, message: ci.message, affectedRows: [] });
|
|
203
|
+
}
|
|
204
|
+
grouped.get(key).affectedRows.push({
|
|
205
|
+
row: issue.rowNumber ?? -1,
|
|
206
|
+
value: ci.data ?? '',
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
for (const { columnName, message, affectedRows } of grouped.values()) {
|
|
211
|
+
issues.push({
|
|
212
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
213
|
+
category: types_2.PreValidationCategory.OPTION_SET,
|
|
214
|
+
columnName,
|
|
215
|
+
propertySlug: (0, data_transformer_functions_1.removeOptionOrFamilySuffix)(columnName),
|
|
216
|
+
propertyType: 'multi_select',
|
|
217
|
+
message,
|
|
218
|
+
affectedRows,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return issues;
|
|
222
|
+
}
|
|
170
223
|
function validateOptionSets(rows, typePropertyMaps) {
|
|
171
224
|
const { optionSetUsingTypePropertiesBySlug } = typePropertyMaps;
|
|
172
225
|
const issues = [];
|
|
173
226
|
const skipColumns = new Set();
|
|
227
|
+
const propertyForColumn = (key) => optionSetUsingTypePropertiesBySlug[key] ??
|
|
228
|
+
optionSetUsingTypePropertiesBySlug[(0, data_transformer_functions_1.removeOptionOrFamilySuffix)(key)];
|
|
174
229
|
const affectedRowsByColumn = {};
|
|
230
|
+
const propertyByColumn = {};
|
|
175
231
|
forEachRow(rows, (row, rowNumber) => {
|
|
176
232
|
for (const [key, value] of Object.entries(row)) {
|
|
177
233
|
if (isEmpty(value))
|
|
178
234
|
continue;
|
|
179
|
-
|
|
235
|
+
const property = propertyForColumn(key);
|
|
236
|
+
if (!property)
|
|
180
237
|
continue;
|
|
181
238
|
if (!affectedRowsByColumn[key])
|
|
182
239
|
affectedRowsByColumn[key] = [];
|
|
183
240
|
affectedRowsByColumn[key].push({ row: rowNumber, value: String(value) });
|
|
241
|
+
propertyByColumn[key] = property;
|
|
184
242
|
}
|
|
185
243
|
});
|
|
186
|
-
for (const [
|
|
187
|
-
if (!affectedRowsByColumn[slug])
|
|
188
|
-
continue;
|
|
244
|
+
for (const [columnName, property] of Object.entries(propertyByColumn)) {
|
|
189
245
|
if (!property.typePropertyOptionSetId) {
|
|
190
246
|
issues.push({
|
|
191
247
|
severity: types_2.PreValidationSeverity.ERROR,
|
|
192
248
|
category: types_2.PreValidationCategory.OPTION_SET,
|
|
193
|
-
columnName
|
|
249
|
+
columnName,
|
|
194
250
|
propertySlug: property.slug,
|
|
195
251
|
propertyType: property.propertyType,
|
|
196
|
-
message: `Property "${
|
|
197
|
-
affectedRows: affectedRowsByColumn[
|
|
252
|
+
message: `Property "${columnName}" is type ${PROPERTY_TYPE_DISPLAY[property.propertyType] ?? property.propertyType} but has no option set attached. Attach an option set to this property or change the property type.`,
|
|
253
|
+
affectedRows: affectedRowsByColumn[columnName],
|
|
198
254
|
});
|
|
199
|
-
skipColumns.add(
|
|
255
|
+
skipColumns.add(columnName);
|
|
200
256
|
}
|
|
201
257
|
else if (!property.options || property.options.length === 0) {
|
|
202
258
|
issues.push({
|
|
203
259
|
severity: types_2.PreValidationSeverity.ERROR,
|
|
204
260
|
category: types_2.PreValidationCategory.OPTION_SET,
|
|
205
|
-
columnName
|
|
261
|
+
columnName,
|
|
206
262
|
propertySlug: property.slug,
|
|
207
263
|
propertyType: property.propertyType,
|
|
208
|
-
message: `Option set for property "${
|
|
209
|
-
affectedRows: affectedRowsByColumn[
|
|
264
|
+
message: `Option set for property "${columnName}" is empty. Values in this column cannot be validated. Populate the option set or remove data from this column.`,
|
|
265
|
+
affectedRows: affectedRowsByColumn[columnName],
|
|
210
266
|
});
|
|
211
|
-
skipColumns.add(
|
|
267
|
+
skipColumns.add(columnName);
|
|
212
268
|
}
|
|
213
269
|
}
|
|
214
270
|
const issuesByColumn = {};
|
|
@@ -216,7 +272,7 @@ function validateOptionSets(rows, typePropertyMaps) {
|
|
|
216
272
|
for (const [key, value] of Object.entries(row)) {
|
|
217
273
|
if (isEmpty(value))
|
|
218
274
|
continue;
|
|
219
|
-
const property =
|
|
275
|
+
const property = propertyForColumn(key);
|
|
220
276
|
if (!property)
|
|
221
277
|
continue;
|
|
222
278
|
if (skipColumns.has(key))
|
|
@@ -598,211 +654,6 @@ function validateAllOverrideSuffixes(rows, config, columnAnalysis) {
|
|
|
598
654
|
}
|
|
599
655
|
return issues;
|
|
600
656
|
}
|
|
601
|
-
async function validateAndResolveProjectIdentifiers(rows, config, client) {
|
|
602
|
-
const isProjectItemLoad = config.loadType.some((lt) => lt === types_2.LoadType.PROJECT_ITEM);
|
|
603
|
-
if (!isProjectItemLoad)
|
|
604
|
-
return [];
|
|
605
|
-
const hasWorkspaceIdentifier = rows.some((row) => row.workspaceIdentifier);
|
|
606
|
-
if (hasWorkspaceIdentifier) {
|
|
607
|
-
return validateWorkspaceIdentifiers(rows, client);
|
|
608
|
-
}
|
|
609
|
-
return validateProjectIds(rows, client);
|
|
610
|
-
}
|
|
611
|
-
async function validateWorkspaceIdentifiers(rows, client) {
|
|
612
|
-
const issues = [];
|
|
613
|
-
const cache = {};
|
|
614
|
-
const uniqueIdentifiers = new Set();
|
|
615
|
-
for (const row of rows) {
|
|
616
|
-
if (row.workspaceIdentifier)
|
|
617
|
-
uniqueIdentifiers.add(row.workspaceIdentifier);
|
|
618
|
-
}
|
|
619
|
-
for (const wsIdentifier of uniqueIdentifiers) {
|
|
620
|
-
try {
|
|
621
|
-
const project = await resolveProjectIdFromWorkspace(client, wsIdentifier);
|
|
622
|
-
cache[wsIdentifier] = project;
|
|
623
|
-
if (!project) {
|
|
624
|
-
const affectedRows = [];
|
|
625
|
-
rows.forEach((row, index) => {
|
|
626
|
-
if (row.workspaceIdentifier === wsIdentifier) {
|
|
627
|
-
affectedRows.push({ row: index + 2, value: wsIdentifier });
|
|
628
|
-
}
|
|
629
|
-
});
|
|
630
|
-
issues.push({
|
|
631
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
632
|
-
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
633
|
-
columnName: 'workspaceIdentifier',
|
|
634
|
-
propertySlug: 'workspaceIdentifier',
|
|
635
|
-
propertyType: 'string',
|
|
636
|
-
message: `Could not resolve workspace identifier "${wsIdentifier}" to a project. Verify the workspace exists and is a PROJECT type workspace.`,
|
|
637
|
-
affectedRows,
|
|
638
|
-
});
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
catch (e) {
|
|
642
|
-
issues.push({
|
|
643
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
644
|
-
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
645
|
-
columnName: 'workspaceIdentifier',
|
|
646
|
-
propertySlug: 'workspaceIdentifier',
|
|
647
|
-
propertyType: 'string',
|
|
648
|
-
message: `Failed to resolve workspace identifier "${wsIdentifier}": ${e.message}`,
|
|
649
|
-
affectedRows: [],
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
if (issues.length === 0) {
|
|
654
|
-
for (const row of rows) {
|
|
655
|
-
if (row.workspaceIdentifier) {
|
|
656
|
-
const project = cache[row.workspaceIdentifier];
|
|
657
|
-
row.projectId = project.id;
|
|
658
|
-
row.projectName = project.name;
|
|
659
|
-
delete row.workspaceIdentifier;
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
return issues;
|
|
664
|
-
}
|
|
665
|
-
async function validateProjectIds(rows, client) {
|
|
666
|
-
const issues = [];
|
|
667
|
-
const nameCache = {};
|
|
668
|
-
const uniqueProjectIds = new Set();
|
|
669
|
-
for (const row of rows) {
|
|
670
|
-
if (row.projectId)
|
|
671
|
-
uniqueProjectIds.add(row.projectId);
|
|
672
|
-
}
|
|
673
|
-
if (uniqueProjectIds.size === 0)
|
|
674
|
-
return [];
|
|
675
|
-
for (const projectId of uniqueProjectIds) {
|
|
676
|
-
try {
|
|
677
|
-
const project = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
678
|
-
entityName: 'project',
|
|
679
|
-
id: projectId,
|
|
680
|
-
skipHydrateRelationships: true,
|
|
681
|
-
});
|
|
682
|
-
if (!project) {
|
|
683
|
-
const affectedRows = [];
|
|
684
|
-
rows.forEach((row, index) => {
|
|
685
|
-
if (row.projectId === projectId) {
|
|
686
|
-
affectedRows.push({ row: index + 2, value: projectId });
|
|
687
|
-
}
|
|
688
|
-
});
|
|
689
|
-
issues.push({
|
|
690
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
691
|
-
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
692
|
-
columnName: 'projectId',
|
|
693
|
-
propertySlug: 'projectId',
|
|
694
|
-
propertyType: 'string',
|
|
695
|
-
message: `Project "${projectId}" not found. Verify the project ID is correct and the project exists.`,
|
|
696
|
-
affectedRows,
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
else {
|
|
700
|
-
nameCache[projectId] = project.name || project.identifier || projectId;
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
catch (e) {
|
|
704
|
-
const affectedRows = [];
|
|
705
|
-
rows.forEach((row, index) => {
|
|
706
|
-
if (row.projectId === projectId) {
|
|
707
|
-
affectedRows.push({ row: index + 2, value: projectId });
|
|
708
|
-
}
|
|
709
|
-
});
|
|
710
|
-
issues.push({
|
|
711
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
712
|
-
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
713
|
-
columnName: 'projectId',
|
|
714
|
-
propertySlug: 'projectId',
|
|
715
|
-
propertyType: 'string',
|
|
716
|
-
message: `Failed to validate project "${projectId}": ${e.message}`,
|
|
717
|
-
affectedRows,
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
if (issues.length === 0) {
|
|
722
|
-
for (const row of rows) {
|
|
723
|
-
if (row.projectId && nameCache[row.projectId]) {
|
|
724
|
-
row.projectName = nameCache[row.projectId];
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
return issues;
|
|
729
|
-
}
|
|
730
|
-
async function resolveProjectIdFromWorkspace(client, workspaceIdentifier) {
|
|
731
|
-
const workspaces = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
732
|
-
entityName: 'workspace',
|
|
733
|
-
criteria: {
|
|
734
|
-
identifier: workspaceIdentifier,
|
|
735
|
-
workspaceType: 'PROJECT',
|
|
736
|
-
},
|
|
737
|
-
skipHydrateRelationships: true,
|
|
738
|
-
});
|
|
739
|
-
if (!workspaces?.length)
|
|
740
|
-
return null;
|
|
741
|
-
const workspaceId = workspaces[0]?.id;
|
|
742
|
-
if (!workspaceId)
|
|
743
|
-
return null;
|
|
744
|
-
const workspace = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
745
|
-
entityName: 'workspace',
|
|
746
|
-
id: workspaceId,
|
|
747
|
-
relations: ['project'],
|
|
748
|
-
skipHydrateRelationships: true,
|
|
749
|
-
});
|
|
750
|
-
const project = workspace?.project;
|
|
751
|
-
if (!project?.id)
|
|
752
|
-
return null;
|
|
753
|
-
return { id: project.id, name: project.name || project.id };
|
|
754
|
-
}
|
|
755
|
-
function validateProjectItemColumns(rows, config) {
|
|
756
|
-
const isProjectItemLoad = config.loadType.some((lt) => lt === types_2.LoadType.PROJECT_ITEM);
|
|
757
|
-
if (!isProjectItemLoad)
|
|
758
|
-
return [];
|
|
759
|
-
const issues = [];
|
|
760
|
-
const hasWorkspaceIdentifier = rows.some((row) => row.workspaceIdentifier !== undefined);
|
|
761
|
-
const hasProjectId = rows.some((row) => row.projectId !== undefined);
|
|
762
|
-
if (hasWorkspaceIdentifier && hasProjectId) {
|
|
763
|
-
issues.push({
|
|
764
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
765
|
-
category: CONFIG_CATEGORY,
|
|
766
|
-
columnName: 'workspaceIdentifier / projectId',
|
|
767
|
-
propertySlug: '',
|
|
768
|
-
propertyType: '',
|
|
769
|
-
message: 'Rows contain both "workspaceIdentifier" and "projectId" columns. Use one or the other to identify the target project.',
|
|
770
|
-
affectedRows: [],
|
|
771
|
-
});
|
|
772
|
-
return issues;
|
|
773
|
-
}
|
|
774
|
-
if (!hasWorkspaceIdentifier && !hasProjectId) {
|
|
775
|
-
issues.push({
|
|
776
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
777
|
-
category: CONFIG_CATEGORY,
|
|
778
|
-
columnName: 'workspaceIdentifier / projectId',
|
|
779
|
-
propertySlug: '',
|
|
780
|
-
propertyType: '',
|
|
781
|
-
message: 'PROJECT_ITEM loads require a "workspaceIdentifier" or "projectId" column (or a config-level workspaceIdentifier) to identify the target project.',
|
|
782
|
-
affectedRows: [],
|
|
783
|
-
});
|
|
784
|
-
return issues;
|
|
785
|
-
}
|
|
786
|
-
const columnName = hasWorkspaceIdentifier ? 'workspaceIdentifier' : 'projectId';
|
|
787
|
-
const emptyRows = [];
|
|
788
|
-
forEachRow(rows, (row, rowNumber) => {
|
|
789
|
-
if (isEmpty(row[columnName])) {
|
|
790
|
-
emptyRows.push({ row: rowNumber, value: '' });
|
|
791
|
-
}
|
|
792
|
-
});
|
|
793
|
-
if (emptyRows.length > 0) {
|
|
794
|
-
issues.push({
|
|
795
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
796
|
-
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
797
|
-
columnName,
|
|
798
|
-
propertySlug: columnName,
|
|
799
|
-
propertyType: 'string',
|
|
800
|
-
message: `"${columnName}" cannot be empty for project-item rows. ${emptyRows.length} row(s) have an empty value.`,
|
|
801
|
-
affectedRows: emptyRows,
|
|
802
|
-
});
|
|
803
|
-
}
|
|
804
|
-
return issues;
|
|
805
|
-
}
|
|
806
657
|
function validateStaticIdentifierConflicts(config) {
|
|
807
658
|
const issues = [];
|
|
808
659
|
const conditionalTargets = new Set((config.conditionalColumns || []).map((col) => col.toProperty));
|
|
@@ -827,211 +678,6 @@ function validateStaticIdentifierConflicts(config) {
|
|
|
827
678
|
}
|
|
828
679
|
return issues;
|
|
829
680
|
}
|
|
830
|
-
function validateAssortmentColumns(rows, config) {
|
|
831
|
-
const isAssortmentLoad = config.loadType.some((lt) => lt === types_2.LoadType.ASSORTMENT);
|
|
832
|
-
if (!isAssortmentLoad)
|
|
833
|
-
return [];
|
|
834
|
-
const issues = [];
|
|
835
|
-
const hasAssortmentId = rows.some((row) => row.assortmentId !== undefined);
|
|
836
|
-
const hasAssortmentIdentifier = rows.some((row) => row.assortmentIdentifier !== undefined);
|
|
837
|
-
const assortmentIdFromConditions = (config.conditionalColumns || []).some((col) => (col.toProperty === 'assortmentId' || col.toProperty === 'assortmentIdentifier') && col.conditions?.length);
|
|
838
|
-
if (!hasAssortmentId && !hasAssortmentIdentifier) {
|
|
839
|
-
issues.push({
|
|
840
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
841
|
-
category: CONFIG_CATEGORY,
|
|
842
|
-
columnName: 'assortmentId / assortmentIdentifier',
|
|
843
|
-
propertySlug: '',
|
|
844
|
-
propertyType: '',
|
|
845
|
-
message: 'ASSORTMENT loads require an "assortmentId" or "assortmentIdentifier" column (or a config-level assortmentId/assortmentIdentifier) to identify the target assortment.',
|
|
846
|
-
affectedRows: [],
|
|
847
|
-
});
|
|
848
|
-
return issues;
|
|
849
|
-
}
|
|
850
|
-
const bothRows = [];
|
|
851
|
-
forEachRow(rows, (row, rowNumber) => {
|
|
852
|
-
const hasId = !isEmpty(row.assortmentId);
|
|
853
|
-
const hasIdent = !isEmpty(row.assortmentIdentifier);
|
|
854
|
-
if (hasId && hasIdent) {
|
|
855
|
-
bothRows.push({ row: rowNumber, value: `${row.assortmentId} / ${row.assortmentIdentifier}` });
|
|
856
|
-
}
|
|
857
|
-
});
|
|
858
|
-
if (bothRows.length > 0) {
|
|
859
|
-
issues.push({
|
|
860
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
861
|
-
category: CONFIG_CATEGORY,
|
|
862
|
-
columnName: 'assortmentId / assortmentIdentifier',
|
|
863
|
-
propertySlug: '',
|
|
864
|
-
propertyType: '',
|
|
865
|
-
message: `${bothRows.length} row(s) have both "assortmentId" and "assortmentIdentifier". Each row must use one or the other.`,
|
|
866
|
-
affectedRows: bothRows,
|
|
867
|
-
});
|
|
868
|
-
return issues;
|
|
869
|
-
}
|
|
870
|
-
const emptyIdRows = [];
|
|
871
|
-
const emptyIdentRows = [];
|
|
872
|
-
forEachRow(rows, (row, rowNumber) => {
|
|
873
|
-
if (hasAssortmentId && row.assortmentId !== undefined) {
|
|
874
|
-
if (isEmpty(row.assortmentId)) {
|
|
875
|
-
emptyIdRows.push({ row: rowNumber, value: '' });
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
else if (hasAssortmentId && row.assortmentId === undefined && !assortmentIdFromConditions) {
|
|
879
|
-
emptyIdRows.push({ row: rowNumber, value: '' });
|
|
880
|
-
}
|
|
881
|
-
if (hasAssortmentIdentifier && row.assortmentIdentifier !== undefined) {
|
|
882
|
-
if (isEmpty(row.assortmentIdentifier)) {
|
|
883
|
-
emptyIdentRows.push({ row: rowNumber, value: '' });
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
});
|
|
887
|
-
if (emptyIdRows.length > 0) {
|
|
888
|
-
issues.push({
|
|
889
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
890
|
-
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
891
|
-
columnName: 'assortmentId',
|
|
892
|
-
propertySlug: 'assortmentId',
|
|
893
|
-
propertyType: 'string',
|
|
894
|
-
message: `"assortmentId" cannot be empty for assortment rows. ${emptyIdRows.length} row(s) have an empty value.`,
|
|
895
|
-
affectedRows: emptyIdRows,
|
|
896
|
-
});
|
|
897
|
-
}
|
|
898
|
-
if (emptyIdentRows.length > 0) {
|
|
899
|
-
issues.push({
|
|
900
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
901
|
-
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
902
|
-
columnName: 'assortmentIdentifier',
|
|
903
|
-
propertySlug: 'assortmentIdentifier',
|
|
904
|
-
propertyType: 'string',
|
|
905
|
-
message: `"assortmentIdentifier" cannot be empty for assortment rows. ${emptyIdentRows.length} row(s) have an empty value.`,
|
|
906
|
-
affectedRows: emptyIdentRows,
|
|
907
|
-
});
|
|
908
|
-
}
|
|
909
|
-
return issues;
|
|
910
|
-
}
|
|
911
|
-
async function validateAndResolveAssortmentIdentifiers(rows, config, client) {
|
|
912
|
-
const isAssortmentLoad = config.loadType.some((lt) => lt === types_2.LoadType.ASSORTMENT);
|
|
913
|
-
if (!isAssortmentLoad)
|
|
914
|
-
return [];
|
|
915
|
-
const hasAssortmentIdentifier = rows.some((row) => row.assortmentIdentifier);
|
|
916
|
-
if (hasAssortmentIdentifier) {
|
|
917
|
-
return resolveAssortmentIdentifiers(rows, client);
|
|
918
|
-
}
|
|
919
|
-
return validateAssortmentIds(rows, client);
|
|
920
|
-
}
|
|
921
|
-
async function resolveAssortmentIdentifiers(rows, client) {
|
|
922
|
-
const issues = [];
|
|
923
|
-
const cache = {};
|
|
924
|
-
const uniqueIdentifiers = new Set();
|
|
925
|
-
for (const row of rows) {
|
|
926
|
-
if (row.assortmentIdentifier)
|
|
927
|
-
uniqueIdentifiers.add(row.assortmentIdentifier);
|
|
928
|
-
}
|
|
929
|
-
for (const identifier of uniqueIdentifiers) {
|
|
930
|
-
try {
|
|
931
|
-
const assortments = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
932
|
-
entityName: 'assortment',
|
|
933
|
-
criteria: { identifier },
|
|
934
|
-
skipHydrateRelationships: true,
|
|
935
|
-
});
|
|
936
|
-
if (!assortments?.length) {
|
|
937
|
-
cache[identifier] = null;
|
|
938
|
-
const affectedRows = [];
|
|
939
|
-
rows.forEach((row, index) => {
|
|
940
|
-
if (row.assortmentIdentifier === identifier) {
|
|
941
|
-
affectedRows.push({ row: index + 2, value: identifier });
|
|
942
|
-
}
|
|
943
|
-
});
|
|
944
|
-
issues.push({
|
|
945
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
946
|
-
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
947
|
-
columnName: 'assortmentIdentifier',
|
|
948
|
-
propertySlug: 'assortmentIdentifier',
|
|
949
|
-
propertyType: 'string',
|
|
950
|
-
message: `Assortment with identifier "${identifier}" not found. Verify the identifier is correct and the assortment exists.`,
|
|
951
|
-
affectedRows,
|
|
952
|
-
});
|
|
953
|
-
}
|
|
954
|
-
else {
|
|
955
|
-
const assortment = assortments[0];
|
|
956
|
-
cache[identifier] = { id: assortment.id, name: assortment.name || assortment.id };
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
catch (e) {
|
|
960
|
-
issues.push({
|
|
961
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
962
|
-
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
963
|
-
columnName: 'assortmentIdentifier',
|
|
964
|
-
propertySlug: 'assortmentIdentifier',
|
|
965
|
-
propertyType: 'string',
|
|
966
|
-
message: `Failed to resolve assortment identifier "${identifier}": ${e.message}`,
|
|
967
|
-
affectedRows: [],
|
|
968
|
-
});
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
if (issues.length === 0) {
|
|
972
|
-
for (const row of rows) {
|
|
973
|
-
if (row.assortmentIdentifier) {
|
|
974
|
-
const assortment = cache[row.assortmentIdentifier];
|
|
975
|
-
row.assortmentId = assortment.id;
|
|
976
|
-
row.assortmentName = assortment.name;
|
|
977
|
-
delete row.assortmentIdentifier;
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
return issues;
|
|
982
|
-
}
|
|
983
|
-
async function validateAssortmentIds(rows, client) {
|
|
984
|
-
const issues = [];
|
|
985
|
-
const nameCache = {};
|
|
986
|
-
const uniqueIds = new Set();
|
|
987
|
-
for (const row of rows) {
|
|
988
|
-
if (row.assortmentId)
|
|
989
|
-
uniqueIds.add(row.assortmentId);
|
|
990
|
-
}
|
|
991
|
-
if (uniqueIds.size === 0)
|
|
992
|
-
return [];
|
|
993
|
-
for (const assortmentId of uniqueIds) {
|
|
994
|
-
try {
|
|
995
|
-
const assortment = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
996
|
-
entityName: 'assortment',
|
|
997
|
-
id: assortmentId,
|
|
998
|
-
skipHydrateRelationships: true,
|
|
999
|
-
});
|
|
1000
|
-
if (assortment) {
|
|
1001
|
-
nameCache[assortmentId] = assortment.name || assortmentId;
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
catch (e) {
|
|
1005
|
-
const affectedRows = [];
|
|
1006
|
-
rows.forEach((row, index) => {
|
|
1007
|
-
if (row.assortmentId === assortmentId) {
|
|
1008
|
-
affectedRows.push({ row: index + 2, value: assortmentId });
|
|
1009
|
-
}
|
|
1010
|
-
});
|
|
1011
|
-
const parsedDetails = typeof e?.details === 'string' ? JSON.parse(e.details).statusCode : e?.details?.statusCode;
|
|
1012
|
-
const message = parsedDetails === 404
|
|
1013
|
-
? `Assortment "${assortmentId}" not found. Verify the assortment ID is correct and the assortment exists.`
|
|
1014
|
-
: `Failed to validate assortment "${assortmentId}": ${e.message}`;
|
|
1015
|
-
issues.push({
|
|
1016
|
-
severity: types_2.PreValidationSeverity.ERROR,
|
|
1017
|
-
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
1018
|
-
columnName: 'assortmentId',
|
|
1019
|
-
propertySlug: 'assortmentId',
|
|
1020
|
-
propertyType: 'string',
|
|
1021
|
-
message,
|
|
1022
|
-
affectedRows,
|
|
1023
|
-
});
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
if (issues.length === 0) {
|
|
1027
|
-
for (const row of rows) {
|
|
1028
|
-
if (row.assortmentId && nameCache[row.assortmentId]) {
|
|
1029
|
-
row.assortmentName = nameCache[row.assortmentId];
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
return issues;
|
|
1034
|
-
}
|
|
1035
681
|
function validatePartialAssortmentConfig(rows, config) {
|
|
1036
682
|
const isAssortmentLoad = config.loadType.some((lt) => lt === types_2.LoadType.ASSORTMENT);
|
|
1037
683
|
if (!isAssortmentLoad || !config.partialAssortmentUpdate)
|
|
@@ -1130,6 +776,107 @@ function buildObjectRefColumnChecks(typesByPath, isItemBased) {
|
|
|
1130
776
|
}
|
|
1131
777
|
return checks;
|
|
1132
778
|
}
|
|
779
|
+
async function validateObjectReferences(rows, typesByPath, client) {
|
|
780
|
+
const objectRefColumns = [];
|
|
781
|
+
for (const typePath of Object.keys(typesByPath ?? {})) {
|
|
782
|
+
const typeObj = typesByPath[typePath];
|
|
783
|
+
for (const prop of typeObj?.objectReferenceProperties ?? []) {
|
|
784
|
+
objectRefColumns.push({
|
|
785
|
+
slug: prop.slug,
|
|
786
|
+
rootType: prop.referencedTypeRootSlug,
|
|
787
|
+
referencedTypePath: prop.referencedTypePath,
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
if (objectRefColumns.length === 0)
|
|
792
|
+
return [];
|
|
793
|
+
const fedIdsByRootType = {};
|
|
794
|
+
const prefixFedId = (fedId, referencedTypePath) => {
|
|
795
|
+
if (referencedTypePath?.startsWith('custom-entity') && !fedId.startsWith('custom-entity:')) {
|
|
796
|
+
return `${referencedTypePath}:${fedId}`;
|
|
797
|
+
}
|
|
798
|
+
return fedId;
|
|
799
|
+
};
|
|
800
|
+
for (const row of rows) {
|
|
801
|
+
for (const ref of objectRefColumns) {
|
|
802
|
+
if (!ref.rootType)
|
|
803
|
+
continue;
|
|
804
|
+
const variants = (0, entities_helper_2.getPropertyVariants)(row, ref.slug, 'values');
|
|
805
|
+
for (const rawValue of variants) {
|
|
806
|
+
if (isEmpty(rawValue))
|
|
807
|
+
continue;
|
|
808
|
+
const fedId = prefixFedId(String(rawValue), ref.referencedTypePath);
|
|
809
|
+
if (!fedIdsByRootType[ref.rootType])
|
|
810
|
+
fedIdsByRootType[ref.rootType] = [];
|
|
811
|
+
fedIdsByRootType[ref.rootType].push(fedId);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
const limit = pLimit(5);
|
|
816
|
+
const resolvedFedIds = new Set();
|
|
817
|
+
for (const rootType of Object.keys(fedIdsByRootType)) {
|
|
818
|
+
const uniqueFedIds = [...new Set(fedIdsByRootType[rootType])];
|
|
819
|
+
if (uniqueFedIds.length === 0)
|
|
820
|
+
continue;
|
|
821
|
+
const chunks = (0, chunk_by_url_length_1.chunkByUrlLength)(uniqueFedIds);
|
|
822
|
+
const promises = [];
|
|
823
|
+
for (const chunk of chunks) {
|
|
824
|
+
if (!chunk?.length)
|
|
825
|
+
continue;
|
|
826
|
+
promises.push(limit(async () => {
|
|
827
|
+
const batch = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
828
|
+
entityName: rootType,
|
|
829
|
+
federatedIds: (0, lodash_1.uniq)(chunk),
|
|
830
|
+
skipHydrateRelationships: true,
|
|
831
|
+
});
|
|
832
|
+
if (Array.isArray(batch)) {
|
|
833
|
+
for (const entity of batch) {
|
|
834
|
+
if (entity?.federatedId)
|
|
835
|
+
resolvedFedIds.add(entity.federatedId);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}));
|
|
839
|
+
}
|
|
840
|
+
await Promise.all(promises);
|
|
841
|
+
}
|
|
842
|
+
const missingByColumnAndValue = {};
|
|
843
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
844
|
+
for (const ref of objectRefColumns) {
|
|
845
|
+
if (!ref.rootType)
|
|
846
|
+
continue;
|
|
847
|
+
const variants = (0, entities_helper_2.getPropertyVariants)(row, ref.slug, 'keyValue');
|
|
848
|
+
for (const variant of variants) {
|
|
849
|
+
if (isEmpty(variant.value))
|
|
850
|
+
continue;
|
|
851
|
+
const rawValue = String(variant.value);
|
|
852
|
+
const lookupKey = prefixFedId(rawValue, ref.referencedTypePath);
|
|
853
|
+
if (resolvedFedIds.has(lookupKey))
|
|
854
|
+
continue;
|
|
855
|
+
if (!missingByColumnAndValue[variant.key])
|
|
856
|
+
missingByColumnAndValue[variant.key] = new Map();
|
|
857
|
+
const byValue = missingByColumnAndValue[variant.key];
|
|
858
|
+
if (!byValue.has(rawValue))
|
|
859
|
+
byValue.set(rawValue, []);
|
|
860
|
+
byValue.get(rawValue).push({ row: rowNumber, value: rawValue });
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
const issues = [];
|
|
865
|
+
for (const [columnName, byValue] of Object.entries(missingByColumnAndValue)) {
|
|
866
|
+
for (const [missingValue, affectedRows] of byValue) {
|
|
867
|
+
issues.push({
|
|
868
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
869
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
870
|
+
columnName,
|
|
871
|
+
propertySlug: columnName,
|
|
872
|
+
propertyType: 'object_reference',
|
|
873
|
+
message: `Value "${missingValue}" does not match any existing entity for object reference property "${columnName}".`,
|
|
874
|
+
affectedRows,
|
|
875
|
+
});
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
return issues;
|
|
879
|
+
}
|
|
1133
880
|
const NUMERIC_PROPERTY_TYPES = new Set(['number', 'currency', 'percent', 'sequence']);
|
|
1134
881
|
function validateNumberPrecision(rows, typePropertyMaps) {
|
|
1135
882
|
const { typePropertiesBySlug } = typePropertyMaps;
|