cassproject 5.0.7 → 5.0.8

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 CHANGED
@@ -50,6 +50,10 @@ Development unit tests presume you have a CaSS Repository running on `localhost:
50
50
 
51
51
  # Changelog
52
52
 
53
+ ## 5.0.8
54
+ * Security updates
55
+ * CTDL-ASN import fixes
56
+
53
57
  ## 5.0.7
54
58
  * Security updates
55
59
  * Assertions with the same registration will no longer propagate to the same inferred assertions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cassproject",
3
- "version": "5.0.7",
3
+ "version": "5.0.8",
4
4
  "description": "Competency and Skills Service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -193,18 +193,18 @@
193
193
  "chai": "4.5.0",
194
194
  "concurrently": "^9.2.1",
195
195
  "convert-hrtime": "^5.0.0",
196
- "cypress": "^15.7.1",
196
+ "cypress": "^15.8.1",
197
197
  "cypress-fail-fast": "^7.1.1",
198
- "eslint": "^9.39.1",
198
+ "eslint": "^9.39.2",
199
199
  "fake-indexeddb": "^6.2.5",
200
200
  "mocha": "^11.7.5",
201
201
  "node-polyfill-webpack-plugin": "^4.1.0",
202
202
  "nodemon": "^3.1.11",
203
203
  "nyc": "^17.1.0",
204
- "sinon": "^21.0.0",
204
+ "sinon": "^21.0.1",
205
205
  "url-polyfill": "^1.1.14",
206
206
  "wait-on": "^9.0.3",
207
- "webpack": "^5.103.0",
207
+ "webpack": "^5.104.1",
208
208
  "webpack-cli": "^6.0.1"
209
209
  },
210
210
  "packageManager": "npm@11.3.0+sha512.96eb611483f49c55f7fa74df61b588de9e213f80a256728e6798ddc67176c7b07e4a1cfc7de8922422cbce02543714367037536955221fa451b0c4fefaf20c66"
@@ -131,6 +131,7 @@ module.exports = class CTDLASNCSVConceptImport {
131
131
  encoding: "UTF-8",
132
132
  complete: async function(results) {
133
133
  let tabularData = results["data"];
134
+ let errors = []; // Collect all errors to display at once
134
135
  try {
135
136
  for (let data of tabularData) {
136
137
  for (let [key, value] of Object.entries(data)) {
@@ -148,30 +149,37 @@ module.exports = class CTDLASNCSVConceptImport {
148
149
  validationRules.hierarchyRules
149
150
  );
150
151
  if (hierarchyError) {
151
- failure(hierarchyError);
152
- return;
152
+ errors.push(hierarchyError);
153
153
  }
154
154
  }
155
155
  const terms = JSON.parse(JSON.stringify((await EcRemote.getExpectingObject("https://schema.cassproject.org/0.4/jsonld1.1/ceasn2cassConceptsTerms"))));
156
156
  let schemeArray = [];
157
157
  let concepts = [];
158
+ let rowsWithErrors = new Set(); // Track rows that have errors
158
159
  for (let each = 0; each < tabularData.length; each++) {
159
160
  let pretranslatedE = tabularData[each];
160
161
  // Skip extra lines if found in file
161
162
  if (!pretranslatedE) {
162
163
  continue;
163
164
  }
165
+
166
+ // Validate basic required fields and collect errors
167
+ let rowHasError = false;
164
168
  if (!pretranslatedE["@id"]) {
165
- failure(`Row ${each + 2}: is missing an @id`);
166
- return;
169
+ errors.push(`Row ${each + 2}: is missing an @id`);
170
+ rowHasError = true;
167
171
  }
168
172
  if (!pretranslatedE["@type"]) {
169
- failure(`Row ${each + 2}: is missing a @type`);
170
- return;
173
+ errors.push(`Row ${each + 2}: is missing a @type`);
174
+ rowHasError = true;
171
175
  }
172
- if (!pretranslatedE["@id"].startsWith('http') && !pretranslatedE["@id"].startsWith('ce-')) {
173
- failure(`row ${each + 2}: @id must be a valid URI or start with 'ce-'`)
174
- return;
176
+ if (pretranslatedE["@id"] && !pretranslatedE["@id"].startsWith('http') && !pretranslatedE["@id"].startsWith('ce-')) {
177
+ errors.push(`Row ${each + 2}: @id must be a valid URI or start with 'ce-'`);
178
+ rowHasError = true;
179
+ }
180
+ if (rowHasError) {
181
+ rowsWithErrors.add(each);
182
+ continue;
175
183
  }
176
184
  if (
177
185
  pretranslatedE["@type"].toLowerCase().startsWith('sample') || pretranslatedE["@type"].toLowerCase().startsWith('instruction')
@@ -181,15 +189,20 @@ module.exports = class CTDLASNCSVConceptImport {
181
189
  if (pretranslatedE["@type"] == "skos:ConceptScheme") {
182
190
  // Validate required properties (only if validation rules provided)
183
191
  if (validationRules && validationRules.requiredProps) {
184
- const validationError = CTDLASNCSVConceptImport.validateRequiredProperties(
192
+ const validationErrors = CTDLASNCSVConceptImport.validateRequiredProperties(
185
193
  pretranslatedE,
186
194
  "skos:ConceptScheme",
187
195
  each + 2,
188
196
  validationRules.requiredProps
189
197
  );
190
- if (validationError) {
191
- failure(validationError);
192
- return;
198
+ if (validationErrors) {
199
+ if (Array.isArray(validationErrors)) {
200
+ errors.push(...validationErrors);
201
+ } else {
202
+ errors.push(validationErrors);
203
+ }
204
+ rowsWithErrors.add(each);
205
+ continue;
193
206
  }
194
207
  }
195
208
  let translator = new EcLinkedData(null, null);
@@ -263,15 +276,20 @@ module.exports = class CTDLASNCSVConceptImport {
263
276
  } else if (pretranslatedE["@type"] == "skos:Concept") {
264
277
  // Validate required properties (only if validation rules provided)
265
278
  if (validationRules && validationRules.requiredProps) {
266
- const validationError = CTDLASNCSVConceptImport.validateRequiredProperties(
279
+ const validationErrors = CTDLASNCSVConceptImport.validateRequiredProperties(
267
280
  pretranslatedE,
268
281
  "skos:Concept",
269
282
  each + 2,
270
283
  validationRules.requiredProps
271
284
  );
272
- if (validationError) {
273
- failure(validationError);
274
- return;
285
+ if (validationErrors) {
286
+ if (Array.isArray(validationErrors)) {
287
+ errors.push(...validationErrors);
288
+ } else {
289
+ errors.push(validationErrors);
290
+ }
291
+ rowsWithErrors.add(each);
292
+ continue;
275
293
  }
276
294
  }
277
295
  let translator = new EcLinkedData(null, null);
@@ -302,8 +320,9 @@ module.exports = class CTDLASNCSVConceptImport {
302
320
  let f = new EcConcept();
303
321
  f.copyFrom(e);
304
322
  if (e["id"] == null) {
305
- failure(`Row ${each + 2}: Concept is missing an id`);
306
- return;
323
+ errors.push(`Row ${each + 2}: Concept is missing an id`);
324
+ rowsWithErrors.add(each);
325
+ continue;
307
326
  }
308
327
  if (
309
328
  EcConcept.template != null &&
@@ -446,15 +465,22 @@ module.exports = class CTDLASNCSVConceptImport {
446
465
  pretranslatedE["@type"] == null ||
447
466
  pretranslatedE["@type"] == ""
448
467
  ) {
449
- failure(`Row ${each + 2}: Missing or empty @type`);
450
- return;
468
+ errors.push(`Row ${each + 2}: Missing or empty @type`);
469
+ rowsWithErrors.add(each);
470
+ continue;
451
471
  } else {
452
- failure(
472
+ errors.push(
453
473
  `Row ${each + 2}: Found unknown type: ` + pretranslatedE["@type"]
454
474
  );
455
- return;
475
+ rowsWithErrors.add(each);
476
+ continue;
456
477
  }
457
478
  }
479
+ // If there are any errors, report them all at once
480
+ if (errors.length > 0) {
481
+ failure(errors);
482
+ return;
483
+ }
458
484
  success(schemeArray, concepts);
459
485
  },
460
486
  error: failure
@@ -475,6 +501,7 @@ module.exports = class CTDLASNCSVConceptImport {
475
501
  encoding: "UTF-8",
476
502
  complete: async function(results) {
477
503
  let tabularData = results["data"];
504
+ let errors = []; // Collect all errors to display at once
478
505
  try {
479
506
  for (let data of tabularData) {
480
507
  for (let [key, value] of Object.entries(data)) {
@@ -492,26 +519,33 @@ module.exports = class CTDLASNCSVConceptImport {
492
519
  validationRules.hierarchyRules
493
520
  );
494
521
  if (hierarchyError) {
495
- failure(hierarchyError);
496
- return;
522
+ errors.push(hierarchyError);
497
523
  }
498
524
  }
499
525
  const terms = JSON.parse(JSON.stringify((await EcRemote.getExpectingObject("https://schema.cassproject.org/0.4/jsonld1.1/ceasn2cassConceptsTerms"))));
500
526
  let schemeArray = [];
501
527
  let concepts = [];
528
+ let rowsWithErrors = new Set(); // Track rows that have errors
502
529
  for (let each = 0; each < tabularData.length; each++) {
503
530
  let pretranslatedE = tabularData[each];
504
531
  // Skip extra lines if found in file
505
532
  if (!pretranslatedE) {
506
533
  continue;
507
534
  }
535
+
536
+ // Validate basic required fields and collect errors
537
+ let rowHasError = false;
508
538
  if (!pretranslatedE["@id"]) {
509
- failure(`Row ${each + 2}: is missing an @id`);
510
- return;
539
+ errors.push(`Row ${each + 2}: is missing an @id`);
540
+ rowHasError = true;
511
541
  }
512
542
  if (!pretranslatedE["@type"]) {
513
- failure(`Row ${each + 2}: is missing a @type`);
514
- return;
543
+ errors.push(`Row ${each + 2}: is missing a @type`);
544
+ rowHasError = true;
545
+ }
546
+ if (rowHasError) {
547
+ rowsWithErrors.add(each);
548
+ continue;
515
549
  }
516
550
  if (
517
551
  pretranslatedE["@type"].toLowerCase().startsWith('sample') || pretranslatedE["@type"].toLowerCase().startsWith('instruction')
@@ -521,15 +555,20 @@ module.exports = class CTDLASNCSVConceptImport {
521
555
  if (pretranslatedE["@type"] == "asn:ProgressionModel") {
522
556
  // Validate required properties (only if validation rules provided)
523
557
  if (validationRules && validationRules.requiredProps) {
524
- const validationError = CTDLASNCSVConceptImport.validateRequiredProperties(
558
+ const validationErrors = CTDLASNCSVConceptImport.validateRequiredProperties(
525
559
  pretranslatedE,
526
560
  "asn:ProgressionModel",
527
561
  each + 2,
528
562
  validationRules.requiredProps
529
563
  );
530
- if (validationError) {
531
- failure(validationError);
532
- return;
564
+ if (validationErrors) {
565
+ if (Array.isArray(validationErrors)) {
566
+ errors.push(...validationErrors);
567
+ } else {
568
+ errors.push(validationErrors);
569
+ }
570
+ rowsWithErrors.add(each);
571
+ continue;
533
572
  }
534
573
  }
535
574
  let translator = new EcLinkedData(null, null);
@@ -599,15 +638,20 @@ module.exports = class CTDLASNCSVConceptImport {
599
638
  } else if (pretranslatedE["@type"] == "asn:ProgressionLevel") {
600
639
  // Validate required properties (only if validation rules provided)
601
640
  if (validationRules && validationRules.requiredProps) {
602
- const validationError = CTDLASNCSVConceptImport.validateRequiredProperties(
641
+ const validationErrors = CTDLASNCSVConceptImport.validateRequiredProperties(
603
642
  pretranslatedE,
604
643
  "asn:ProgressionLevel",
605
644
  each + 2,
606
645
  validationRules.requiredProps
607
646
  );
608
- if (validationError) {
609
- failure(validationError);
610
- return;
647
+ if (validationErrors) {
648
+ if (Array.isArray(validationErrors)) {
649
+ errors.push(...validationErrors);
650
+ } else {
651
+ errors.push(validationErrors);
652
+ }
653
+ rowsWithErrors.add(each);
654
+ continue;
611
655
  }
612
656
  }
613
657
  let translator = new EcLinkedData(null, null);
@@ -638,8 +682,9 @@ module.exports = class CTDLASNCSVConceptImport {
638
682
  let f = new EcConcept();
639
683
  f.copyFrom(e);
640
684
  if (e["id"] == null) {
641
- failure(`Row ${each + 2}: Concept is missing an id`);
642
- return;
685
+ errors.push(`Row ${each + 2}: Concept is missing an id`);
686
+ rowsWithErrors.add(each);
687
+ continue;
643
688
  }
644
689
  if (
645
690
  EcConcept.template != null &&
@@ -747,15 +792,22 @@ module.exports = class CTDLASNCSVConceptImport {
747
792
  pretranslatedE["@type"] == null ||
748
793
  pretranslatedE["@type"] == ""
749
794
  ) {
750
- failure(`Row ${each + 2}: Missing or empty @type`);
751
- return;
795
+ errors.push(`Row ${each + 2}: Missing or empty @type`);
796
+ rowsWithErrors.add(each);
797
+ continue;
752
798
  } else {
753
- failure(
799
+ errors.push(
754
800
  `Row ${each + 2}: Found unknown type: ` + pretranslatedE["@type"]
755
801
  );
756
- return;
802
+ rowsWithErrors.add(each);
803
+ continue;
757
804
  }
758
805
  }
806
+ // If there are any errors, report them all at once
807
+ if (errors.length > 0) {
808
+ failure(errors);
809
+ return;
810
+ }
759
811
  success(schemeArray, concepts);
760
812
  },
761
813
  error: failure
@@ -155,6 +155,7 @@ module.exports = class CTDLASNCSVImport {
155
155
  encoding: "UTF-8",
156
156
  complete: async function(results) {
157
157
  let tabularData = results["data"];
158
+ let errors = []; // Collect all errors to display at once
158
159
  try {
159
160
  for (let data of tabularData) {
160
161
  for (let [key, value] of Object.entries(data)) {
@@ -172,8 +173,7 @@ module.exports = class CTDLASNCSVImport {
172
173
  validationRules.hierarchyRules
173
174
  );
174
175
  if (hierarchyError) {
175
- failure(hierarchyError);
176
- return;
176
+ errors.push(hierarchyError);
177
177
  }
178
178
  }
179
179
 
@@ -185,6 +185,7 @@ module.exports = class CTDLASNCSVImport {
185
185
  let competencyRows = {};
186
186
  let relations = [];
187
187
  let relationById = {};
188
+ let rowsWithErrors = new Set(); // Track rows that have errors to avoid duplicate processing
188
189
  for (let i = 0; i < tabularData.length; i++) {
189
190
  if (!tabularData[i]) {
190
191
  continue;
@@ -194,7 +195,7 @@ module.exports = class CTDLASNCSVImport {
194
195
  if (!pretranslatedE) {
195
196
  continue;
196
197
  }
197
- if (pretranslatedE["@type"].toLowerCase() &&
198
+ if (pretranslatedE["@type"] && pretranslatedE["@type"].toLowerCase() &&
198
199
  (pretranslatedE["@type"].toLowerCase().startsWith('sample') || pretranslatedE["@type"].toLowerCase().startsWith('instruction'))
199
200
  ) {
200
201
  continue;
@@ -211,17 +212,24 @@ module.exports = class CTDLASNCSVImport {
211
212
  continue;
212
213
  }
213
214
  }
215
+
216
+ // Validate basic required fields and collect errors
217
+ let rowHasError = false;
214
218
  if (!pretranslatedE["@id"]) {
215
- failure(`Row ${i + 2}: is missing an @id`)
216
- return;
219
+ errors.push(`Row ${i + 2}: is missing an @id`);
220
+ rowHasError = true;
217
221
  }
218
222
  if (!pretranslatedE["@type"]) {
219
- failure(`Row ${i + 2}: is missing a @type`);
220
- return;
223
+ errors.push(`Row ${i + 2}: is missing a @type`);
224
+ rowHasError = true;
225
+ }
226
+ if (pretranslatedE["@id"] && !pretranslatedE["@id"].startsWith('http') && !pretranslatedE["@id"].startsWith('ce-')) {
227
+ errors.push(`Row ${i + 2}: @id must be a valid URI or start with 'ce-'`);
228
+ rowHasError = true;
221
229
  }
222
- if (!pretranslatedE["@id"].startsWith('http') && !pretranslatedE["@id"].startsWith('ce-')) {
223
- failure(`row ${i + 2}: @id must be a valid URI or start with 'ce-'`)
224
- return;
230
+ if (rowHasError) {
231
+ rowsWithErrors.add(i);
232
+ continue;
225
233
  }
226
234
  if (
227
235
  pretranslatedE["@type"] ==
@@ -229,15 +237,20 @@ module.exports = class CTDLASNCSVImport {
229
237
  ) {
230
238
  // Validate required properties (only if validation rules provided)
231
239
  if (validationRules && validationRules.requiredProps) {
232
- const validationError = CTDLASNCSVImport.validateRequiredProperties(
240
+ const validationErrors = CTDLASNCSVImport.validateRequiredProperties(
233
241
  pretranslatedE,
234
242
  "ceasn:CompetencyFramework",
235
243
  i + 2,
236
244
  validationRules.requiredProps
237
245
  );
238
- if (validationError) {
239
- failure(validationError);
240
- return;
246
+ if (validationErrors) {
247
+ if (Array.isArray(validationErrors)) {
248
+ errors.push(...validationErrors);
249
+ } else {
250
+ errors.push(validationErrors);
251
+ }
252
+ rowsWithErrors.add(i);
253
+ continue;
241
254
  }
242
255
  }
243
256
 
@@ -251,7 +264,9 @@ module.exports = class CTDLASNCSVImport {
251
264
  try {
252
265
  let existing = await EcRepository.get(translator.id);
253
266
  if (existing && existing.type !== 'Framework') {
254
- return failure(`Row ${i + 2}: ${translator.id} already exists as a ${existing.type}`);
267
+ errors.push(`Row ${i + 2}: ${translator.id} already exists as a ${existing.type}`);
268
+ rowsWithErrors.add(i);
269
+ continue;
255
270
  }
256
271
  } catch (e) {
257
272
  console.error(e);
@@ -371,15 +386,20 @@ module.exports = class CTDLASNCSVImport {
371
386
  ) {
372
387
  // Validate required properties (only if validation rules provided)
373
388
  if (validationRules && validationRules.requiredProps) {
374
- const validationError = CTDLASNCSVImport.validateRequiredProperties(
389
+ const validationErrors = CTDLASNCSVImport.validateRequiredProperties(
375
390
  pretranslatedE,
376
391
  "ceasn:Competency",
377
392
  i + 2,
378
393
  validationRules.requiredProps
379
394
  );
380
- if (validationError) {
381
- failure(validationError);
382
- return;
395
+ if (validationErrors) {
396
+ if (Array.isArray(validationErrors)) {
397
+ errors.push(...validationErrors);
398
+ } else {
399
+ errors.push(validationErrors);
400
+ }
401
+ rowsWithErrors.add(i);
402
+ continue;
383
403
  }
384
404
  }
385
405
 
@@ -418,8 +438,9 @@ module.exports = class CTDLASNCSVImport {
418
438
  let f = new EcCompetency();
419
439
  f.copyFrom(e);
420
440
  if (e["id"] == null) {
421
- failure(`Row ${i+2}: Competency is missing an id`);
422
- return;
441
+ errors.push(`Row ${i+2}: Competency is missing an id`);
442
+ rowsWithErrors.add(i);
443
+ continue;
423
444
  }
424
445
  if (e["ceasn:isPartOf"] != null) {
425
446
  let shortId = EcRemoteLinkedData.trimVersionFromUrl(e["ceasn:isPartOf"]);
@@ -461,10 +482,11 @@ module.exports = class CTDLASNCSVImport {
461
482
  }
462
483
  }
463
484
  if (!done) {
464
- failure(
485
+ errors.push(
465
486
  `Row ${i+2}: Could not find framework:${e["type"]} (Possibly missing ceasn:isPartOf or ceasn:isChildOf)`
466
487
  );
467
- return;
488
+ rowsWithErrors.add(i);
489
+ continue;
468
490
  }
469
491
  if (parent != null) {
470
492
  if (parent["type"] == "Framework") {
@@ -479,18 +501,20 @@ module.exports = class CTDLASNCSVImport {
479
501
  )
480
502
  ].competency.push(f.shortId());
481
503
  } else {
482
- failure(
504
+ errors.push(
483
505
  `Row ${i+2}: Object cannot trace to framework:` +
484
506
  e["type"]
485
507
  );
486
- return;
508
+ rowsWithErrors.add(i);
509
+ continue;
487
510
  }
488
511
  } else {
489
- failure(
512
+ errors.push(
490
513
  `Row ${i+2}: Object has no framework:` +
491
514
  e["type"]
492
515
  );
493
- return;
516
+ rowsWithErrors.add(i);
517
+ continue;
494
518
  }
495
519
  }
496
520
  if (
@@ -682,15 +706,22 @@ module.exports = class CTDLASNCSVImport {
682
706
  pretranslatedE["@type"] == null ||
683
707
  pretranslatedE["@type"] == ""
684
708
  ) {
685
- failure(`Row ${i+2}: Missing or empty @type`);
686
- return;
709
+ errors.push(`Row ${i+2}: Missing or empty @type`);
710
+ rowsWithErrors.add(i);
711
+ continue;
687
712
  } else {
688
- failure(
713
+ errors.push(
689
714
  `Row ${i+2}: Found unknown type:` + pretranslatedE["@type"]
690
715
  );
691
- return;
716
+ rowsWithErrors.add(i);
717
+ continue;
692
718
  }
693
719
  }
720
+ // If there are any errors, report them all at once
721
+ if (errors.length > 0) {
722
+ failure(errors);
723
+ return;
724
+ }
694
725
  success(frameworkArray, competencies, relations);
695
726
  },
696
727
  error: failure
@@ -712,6 +743,7 @@ module.exports = class CTDLASNCSVImport {
712
743
  encoding: "UTF-8",
713
744
  complete: async function(results) {
714
745
  let tabularData = results["data"];
746
+ let errors = []; // Collect all errors to display at once
715
747
  try {
716
748
  for (let data of tabularData) {
717
749
  for (let [key, value] of Object.entries(data)) {
@@ -729,8 +761,7 @@ module.exports = class CTDLASNCSVImport {
729
761
  validationRules.hierarchyRules
730
762
  );
731
763
  if (hierarchyError) {
732
- failure(hierarchyError);
733
- return;
764
+ errors.push(hierarchyError);
734
765
  }
735
766
  }
736
767
 
@@ -742,23 +773,31 @@ module.exports = class CTDLASNCSVImport {
742
773
  let competencyRows = {};
743
774
  let relations = [];
744
775
  let relationById = {};
776
+ let rowsWithErrors = new Set(); // Track rows that have errors
745
777
  for (let i = 0; i < tabularData.length; i++) {
746
778
  let pretranslatedE = tabularData[i];
747
779
  // Skip extra lines if found in file
748
780
  if (!pretranslatedE) {
749
781
  continue;
750
782
  }
783
+
784
+ // Validate basic required fields and collect errors
785
+ let rowHasError = false;
751
786
  if (!pretranslatedE["@id"]) {
752
- failure(`Row ${i + 2}: is missing an @id`);
753
- return;
787
+ errors.push(`Row ${i + 2}: is missing an @id`);
788
+ rowHasError = true;
754
789
  }
755
- if (!pretranslatedE["@id"].startsWith('http') && !pretranslatedE["@id"].startsWith('ce-')) {
756
- failure(`row ${i + 2}: @id must be a valid URI or start with 'ce-'`)
757
- return;
790
+ if (pretranslatedE["@id"] && !pretranslatedE["@id"].startsWith('http') && !pretranslatedE["@id"].startsWith('ce-')) {
791
+ errors.push(`Row ${i + 2}: @id must be a valid URI or start with 'ce-'`);
792
+ rowHasError = true;
758
793
  }
759
794
  if (!pretranslatedE["@type"]) {
760
- failure(`Row ${i + 2}: is missing a @type`);
761
- return;
795
+ errors.push(`Row ${i + 2}: is missing a @type`);
796
+ rowHasError = true;
797
+ }
798
+ if (rowHasError) {
799
+ rowsWithErrors.add(i);
800
+ continue;
762
801
  }
763
802
  if (
764
803
  pretranslatedE["@type"].toLowerCase().startsWith('sample') || pretranslatedE["@type"].toLowerCase().startsWith('instruction')
@@ -783,15 +822,20 @@ module.exports = class CTDLASNCSVImport {
783
822
  ) {
784
823
  // Validate required properties (only if validation rules provided)
785
824
  if (validationRules && validationRules.requiredProps) {
786
- const validationError = CTDLASNCSVImport.validateRequiredProperties(
825
+ const validationErrors = CTDLASNCSVImport.validateRequiredProperties(
787
826
  pretranslatedE,
788
827
  "ceterms:Collection",
789
828
  i + 2,
790
829
  validationRules.requiredProps
791
830
  );
792
- if (validationError) {
793
- failure(validationError);
794
- return;
831
+ if (validationErrors) {
832
+ if (Array.isArray(validationErrors)) {
833
+ errors.push(...validationErrors);
834
+ } else {
835
+ errors.push(validationErrors);
836
+ }
837
+ rowsWithErrors.add(i);
838
+ continue;
795
839
  }
796
840
  }
797
841
  let translator = new EcLinkedData(null, null);
@@ -867,15 +911,20 @@ module.exports = class CTDLASNCSVImport {
867
911
  ) {
868
912
  // Validate required properties (only if validation rules provided)
869
913
  if (validationRules && validationRules.requiredProps) {
870
- const validationError = CTDLASNCSVImport.validateRequiredProperties(
914
+ const validationErrors = CTDLASNCSVImport.validateRequiredProperties(
871
915
  pretranslatedE,
872
916
  "ceterms:Collection:Competency",
873
917
  i + 2,
874
918
  validationRules.requiredProps
875
919
  );
876
- if (validationError) {
877
- failure(validationError);
878
- return;
920
+ if (validationErrors) {
921
+ if (Array.isArray(validationErrors)) {
922
+ errors.push(...validationErrors);
923
+ } else {
924
+ errors.push(validationErrors);
925
+ }
926
+ rowsWithErrors.add(i);
927
+ continue;
879
928
  }
880
929
  }
881
930
  let translator = new EcLinkedData(null, null);
@@ -901,8 +950,9 @@ module.exports = class CTDLASNCSVImport {
901
950
  let f = new EcCompetency();
902
951
  f.copyFrom(e);
903
952
  if (e["id"] == null) {
904
- failure(`Row ${i+2}: Competency is missing an id`);
905
- return;
953
+ errors.push(`Row ${i+2}: Competency is missing an id`);
954
+ rowsWithErrors.add(i);
955
+ continue;
906
956
  }
907
957
  if (e["ceterms:isMemberOf"] != null) {
908
958
  if (!EcArray.isArray(e["ceterms:isMemberOf"])) {
@@ -1095,15 +1145,22 @@ module.exports = class CTDLASNCSVImport {
1095
1145
  pretranslatedE["@type"] == null ||
1096
1146
  pretranslatedE["@type"] == ""
1097
1147
  ) {
1098
- failure(`Row ${i+2}: Missing or empty @type`);
1099
- return;
1148
+ errors.push(`Row ${i+2}: Missing or empty @type`);
1149
+ rowsWithErrors.add(i);
1150
+ continue;
1100
1151
  } else {
1101
- failure(
1152
+ errors.push(
1102
1153
  `Row ${i+2}: Found unknown type:` + pretranslatedE["@type"]
1103
1154
  );
1104
- return;
1155
+ rowsWithErrors.add(i);
1156
+ continue;
1105
1157
  }
1106
1158
  }
1159
+ // If there are any errors, report them all at once
1160
+ if (errors.length > 0) {
1161
+ failure(errors);
1162
+ return;
1163
+ }
1107
1164
  success(frameworkArray, competencies, relations);
1108
1165
  },
1109
1166
  error: failure