uss-xsd-engine 0.1.1 → 0.2.1

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * uss-xsd-engine v0.1.1
2
+ * uss-xsd-engine v0.2.1
3
3
  * (c) 2026 Bernard Mumble
4
4
  * MIT License
5
5
  */
@@ -72,6 +72,10 @@ var UssXsdEngine = (() => {
72
72
  UNKNOWN_GROUP: "UNKNOWN_GROUP",
73
73
  UNKNOWN_ATTRIBUTE_GROUP: "UNKNOWN_ATTRIBUTE_GROUP",
74
74
  MISSING_BASE_TYPE: "MISSING_BASE_TYPE",
75
+ INVALID_CONSTRAINT_SELECTOR: "INVALID_CONSTRAINT_SELECTOR",
76
+ INVALID_CONSTRAINT_FIELD: "INVALID_CONSTRAINT_FIELD",
77
+ UNKNOWN_KEY_REFERENCE: "UNKNOWN_KEY_REFERENCE",
78
+ DUPLICATE_CONSTRAINT_NAME: "DUPLICATE_CONSTRAINT_NAME",
75
79
  UNSUPPORTED_FEATURE: "UNSUPPORTED_FEATURE",
76
80
  INVALID_OCCURS_RANGE: "INVALID_OCCURS_RANGE",
77
81
  INVALID_DEFAULT_FIXED_COMBINATION: "INVALID_DEFAULT_FIXED_COMBINATION",
@@ -88,6 +92,12 @@ var UssXsdEngine = (() => {
88
92
  XML_VALUE_INVALID: "XML_VALUE_INVALID",
89
93
  XML_ENUMERATION_MISMATCH: "XML_ENUMERATION_MISMATCH",
90
94
  XML_VALUE_REQUIRED: "XML_VALUE_REQUIRED",
95
+ XML_KEY_VIOLATION: "XML_KEY_VIOLATION",
96
+ XML_KEY_NULL_VIOLATION: "XML_KEY_NULL_VIOLATION",
97
+ XML_KEYREF_VIOLATION: "XML_KEYREF_VIOLATION",
98
+ XML_UNIQUE_VIOLATION: "XML_UNIQUE_VIOLATION",
99
+ XML_ANY_STRICT_VALIDATION_FAILED: "XML_ANY_STRICT_VALIDATION_FAILED",
100
+ XML_ANYATTRIBUTE_STRICT_VALIDATION_FAILED: "XML_ANYATTRIBUTE_STRICT_VALIDATION_FAILED",
91
101
  XML_PATTERN_MISMATCH: "XML_PATTERN_MISMATCH",
92
102
  XML_LENGTH_MISMATCH: "XML_LENGTH_MISMATCH",
93
103
  XML_MIN_LENGTH_VIOLATION: "XML_MIN_LENGTH_VIOLATION",
@@ -114,6 +124,9 @@ var UssXsdEngine = (() => {
114
124
  XSD_RESTRICTION_NOT_SUBSET: "XSD_RESTRICTION_NOT_SUBSET",
115
125
  XSD_RESTRICTION_OCCURS_WIDENED: "XSD_RESTRICTION_OCCURS_WIDENED",
116
126
  XSD_RESTRICTION_ATTRIBUTE_WIDENED: "XSD_RESTRICTION_ATTRIBUTE_WIDENED",
127
+ XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE: "XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE",
128
+ XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE: "XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE",
129
+ XSD_RESTRICTION_WILDCARD_INCOMPATIBLE: "XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
117
130
  XSD_INCLUDE_NOT_PROVIDED: "XSD_INCLUDE_NOT_PROVIDED",
118
131
  XSD_IMPORT_NOT_PROVIDED: "XSD_IMPORT_NOT_PROVIDED",
119
132
  XSD_INCLUDE_NAMESPACE_MISMATCH: "XSD_INCLUDE_NAMESPACE_MISMATCH",
@@ -189,6 +202,7 @@ var UssXsdEngine = (() => {
189
202
  },
190
203
  importedSchemas: [],
191
204
  roots: [],
205
+ identityConstraints: [],
192
206
  references: {
193
207
  types: [],
194
208
  refs: [],
@@ -220,7 +234,7 @@ var UssXsdEngine = (() => {
220
234
  function createElementDecl({
221
235
  name = null,
222
236
  qName = null,
223
- namespaceUri: namespaceUri3 = null,
237
+ namespaceUri: namespaceUri4 = null,
224
238
  typeName = null,
225
239
  refName = null,
226
240
  inlineType = null,
@@ -229,6 +243,7 @@ var UssXsdEngine = (() => {
229
243
  defaultValue = null,
230
244
  fixedValue = null,
231
245
  nillable = false,
246
+ identityConstraints = [],
232
247
  line = null,
233
248
  column = null,
234
249
  path = null
@@ -237,7 +252,7 @@ var UssXsdEngine = (() => {
237
252
  kind: "element",
238
253
  name,
239
254
  qName,
240
- namespaceUri: namespaceUri3,
255
+ namespaceUri: namespaceUri4,
241
256
  typeName,
242
257
  refName,
243
258
  inlineType,
@@ -246,6 +261,7 @@ var UssXsdEngine = (() => {
246
261
  defaultValue,
247
262
  fixedValue,
248
263
  nillable,
264
+ identityConstraints,
249
265
  line,
250
266
  column,
251
267
  path
@@ -254,7 +270,7 @@ var UssXsdEngine = (() => {
254
270
  function createAttributeDecl({
255
271
  name = null,
256
272
  qName = null,
257
- namespaceUri: namespaceUri3 = null,
273
+ namespaceUri: namespaceUri4 = null,
258
274
  typeName = null,
259
275
  refName = null,
260
276
  inlineType = null,
@@ -269,7 +285,7 @@ var UssXsdEngine = (() => {
269
285
  kind: "attribute",
270
286
  name,
271
287
  qName,
272
- namespaceUri: namespaceUri3,
288
+ namespaceUri: namespaceUri4,
273
289
  typeName,
274
290
  refName,
275
291
  inlineType,
@@ -284,13 +300,14 @@ var UssXsdEngine = (() => {
284
300
  function createComplexTypeDecl({
285
301
  name = null,
286
302
  qName = null,
287
- namespaceUri: namespaceUri3 = null,
303
+ namespaceUri: namespaceUri4 = null,
288
304
  content = null,
289
305
  attributes = [],
290
306
  derivation = { kind: null, baseTypeName: null },
291
307
  contentModel = "complex",
292
308
  mixed = false,
293
309
  abstract = false,
310
+ identityConstraints = [],
294
311
  line = null,
295
312
  column = null,
296
313
  path = null
@@ -299,13 +316,14 @@ var UssXsdEngine = (() => {
299
316
  kind: "complexType",
300
317
  name,
301
318
  qName,
302
- namespaceUri: namespaceUri3,
319
+ namespaceUri: namespaceUri4,
303
320
  content,
304
321
  attributes,
305
322
  derivation,
306
323
  contentModel,
307
324
  mixed,
308
325
  abstract,
326
+ identityConstraints,
309
327
  line,
310
328
  column,
311
329
  path
@@ -314,7 +332,7 @@ var UssXsdEngine = (() => {
314
332
  function createSimpleTypeDecl({
315
333
  name = null,
316
334
  qName = null,
317
- namespaceUri: namespaceUri3 = null,
335
+ namespaceUri: namespaceUri4 = null,
318
336
  baseTypeName = null,
319
337
  facets = {},
320
338
  enumerations = [],
@@ -326,7 +344,7 @@ var UssXsdEngine = (() => {
326
344
  kind: "simpleType",
327
345
  name,
328
346
  qName,
329
- namespaceUri: namespaceUri3,
347
+ namespaceUri: namespaceUri4,
330
348
  baseTypeName,
331
349
  facets,
332
350
  enumerations,
@@ -338,7 +356,7 @@ var UssXsdEngine = (() => {
338
356
  function createGroupDecl({
339
357
  name,
340
358
  qName = null,
341
- namespaceUri: namespaceUri3 = null,
359
+ namespaceUri: namespaceUri4 = null,
342
360
  content = null,
343
361
  line = null,
344
362
  column = null,
@@ -348,7 +366,7 @@ var UssXsdEngine = (() => {
348
366
  kind: "group",
349
367
  name,
350
368
  qName,
351
- namespaceUri: namespaceUri3,
369
+ namespaceUri: namespaceUri4,
352
370
  content,
353
371
  line,
354
372
  column,
@@ -358,7 +376,7 @@ var UssXsdEngine = (() => {
358
376
  function createAttributeGroupDecl({
359
377
  name,
360
378
  qName = null,
361
- namespaceUri: namespaceUri3 = null,
379
+ namespaceUri: namespaceUri4 = null,
362
380
  attributes = [],
363
381
  line = null,
364
382
  column = null,
@@ -368,7 +386,7 @@ var UssXsdEngine = (() => {
368
386
  kind: "attributeGroup",
369
387
  name,
370
388
  qName,
371
- namespaceUri: namespaceUri3,
389
+ namespaceUri: namespaceUri4,
372
390
  attributes,
373
391
  line,
374
392
  column,
@@ -389,6 +407,37 @@ var UssXsdEngine = (() => {
389
407
  path
390
408
  };
391
409
  }
410
+ function createIdentityConstraint({
411
+ kind = null,
412
+ name = null,
413
+ qName = null,
414
+ namespaceUri: namespaceUri4 = null,
415
+ selector = null,
416
+ fields = [],
417
+ refer = null,
418
+ ownerName = null,
419
+ ownerNamespaceUri = null,
420
+ ownerPath = null,
421
+ line = null,
422
+ column = null,
423
+ path = null
424
+ } = {}) {
425
+ return {
426
+ kind,
427
+ name,
428
+ qName,
429
+ namespaceUri: namespaceUri4,
430
+ selector,
431
+ fields,
432
+ refer,
433
+ ownerName,
434
+ ownerNamespaceUri,
435
+ ownerPath,
436
+ line,
437
+ column,
438
+ path
439
+ };
440
+ }
392
441
  function createSequenceNode({
393
442
  children = [],
394
443
  minOccurs = 1,
@@ -463,9 +512,11 @@ var UssXsdEngine = (() => {
463
512
  }
464
513
  function createAnyNode({
465
514
  namespace = null,
466
- processContents = null,
515
+ processContents = "strict",
467
516
  minOccurs = 1,
468
517
  maxOccurs = 1,
518
+ notNamespace = [],
519
+ notQName = [],
469
520
  line = null,
470
521
  column = null,
471
522
  path = null
@@ -473,9 +524,31 @@ var UssXsdEngine = (() => {
473
524
  return {
474
525
  kind: "any",
475
526
  namespace,
476
- processContents,
527
+ processContents: processContents || "strict",
477
528
  minOccurs,
478
529
  maxOccurs,
530
+ notNamespace,
531
+ notQName,
532
+ line,
533
+ column,
534
+ path
535
+ };
536
+ }
537
+ function createAnyAttributeNode({
538
+ namespace = null,
539
+ processContents = "strict",
540
+ notNamespace = [],
541
+ notQName = [],
542
+ line = null,
543
+ column = null,
544
+ path = null
545
+ } = {}) {
546
+ return {
547
+ kind: "anyAttribute",
548
+ namespace,
549
+ processContents: processContents || "strict",
550
+ notNamespace,
551
+ notQName,
479
552
  line,
480
553
  column,
481
554
  path
@@ -560,8 +633,8 @@ var UssXsdEngine = (() => {
560
633
  namespaceUri: resolveNamespaceUri(schema, parsed.prefix)
561
634
  };
562
635
  }
563
- function makeLookupKey(namespaceUri3, localName3) {
564
- return `${namespaceUri3 || ""}::${localName3 || ""}`;
636
+ function makeLookupKey(namespaceUri4, localName4) {
637
+ return `${namespaceUri4 || ""}::${localName4 || ""}`;
565
638
  }
566
639
  function isBuiltinType(typeName, schema = null) {
567
640
  const q = parseQName(typeName);
@@ -577,41 +650,41 @@ var UssXsdEngine = (() => {
577
650
  function getLocalName(name) {
578
651
  return parseQName(name).localName;
579
652
  }
580
- function lookupBucketByNamespace(bucket, namespaceUri3, localName3) {
581
- if (!bucket || !localName3) return null;
582
- return bucket[makeLookupKey(namespaceUri3, localName3)] || null;
653
+ function lookupBucketByNamespace(bucket, namespaceUri4, localName4) {
654
+ if (!bucket || !localName4) return null;
655
+ return bucket[makeLookupKey(namespaceUri4, localName4)] || null;
583
656
  }
584
- function lookupInSchemaBucket(bucketName, schema, namespaceUri3, localName3) {
585
- return lookupBucketByNamespace(schema?.globals?.[bucketName], namespaceUri3, localName3);
657
+ function lookupInSchemaBucket(bucketName, schema, namespaceUri4, localName4) {
658
+ return lookupBucketByNamespace(schema?.globals?.[bucketName], namespaceUri4, localName4);
586
659
  }
587
- function lookupInImportedSchemas(bucketName, schema, namespaceUri3, localName3, visited = /* @__PURE__ */ new Set()) {
588
- if (!schema || !namespaceUri3) return null;
660
+ function lookupInImportedSchemas(bucketName, schema, namespaceUri4, localName4, visited = /* @__PURE__ */ new Set()) {
661
+ if (!schema || !namespaceUri4) return null;
589
662
  if (visited.has(schema)) return null;
590
663
  visited.add(schema);
591
664
  for (const importedSchema of schema.importedSchemas || []) {
592
665
  if (!importedSchema) continue;
593
- if ((importedSchema.targetNamespace || null) === namespaceUri3) {
666
+ if ((importedSchema.targetNamespace || null) === namespaceUri4) {
594
667
  const direct = lookupInSchemaBucket(
595
668
  bucketName,
596
669
  importedSchema,
597
- namespaceUri3,
598
- localName3
670
+ namespaceUri4,
671
+ localName4
599
672
  );
600
673
  if (direct) return direct;
601
674
  }
602
675
  const nested = lookupInImportedSchemas(
603
676
  bucketName,
604
677
  importedSchema,
605
- namespaceUri3,
606
- localName3,
678
+ namespaceUri4,
679
+ localName4,
607
680
  visited
608
681
  );
609
682
  if (nested) return nested;
610
683
  }
611
684
  return null;
612
685
  }
613
- function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName3, visited = /* @__PURE__ */ new Set()) {
614
- if (!schema || !localName3) return null;
686
+ function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName4, visited = /* @__PURE__ */ new Set()) {
687
+ if (!schema || !localName4) return null;
615
688
  if (visited.has(schema)) return null;
616
689
  visited.add(schema);
617
690
  const targetNs = schema.targetNamespace || null;
@@ -623,14 +696,14 @@ var UssXsdEngine = (() => {
623
696
  bucketName,
624
697
  importedSchema,
625
698
  importedNs,
626
- localName3
699
+ localName4
627
700
  );
628
701
  if (direct) return direct;
629
702
  }
630
703
  const nested = lookupInImportedSchemasForUnprefixed(
631
704
  bucketName,
632
705
  importedSchema,
633
- localName3,
706
+ localName4,
634
707
  visited
635
708
  );
636
709
  if (nested) return nested;
@@ -641,24 +714,24 @@ var UssXsdEngine = (() => {
641
714
  if (!schema || !name) return null;
642
715
  const parsed = parseQName(name);
643
716
  const resolved = resolveQName(schema, name);
644
- const localName3 = resolved.localName;
645
- if (!localName3) return null;
717
+ const localName4 = resolved.localName;
718
+ if (!localName4) return null;
646
719
  if (parsed.prefix) {
647
720
  const direct = lookupInSchemaBucket(
648
721
  bucketName,
649
722
  schema,
650
723
  resolved.namespaceUri,
651
- localName3
724
+ localName4
652
725
  );
653
726
  if (direct) return direct;
654
727
  return lookupInImportedSchemas(
655
728
  bucketName,
656
729
  schema,
657
730
  resolved.namespaceUri,
658
- localName3
731
+ localName4
659
732
  );
660
733
  }
661
- const noNamespace = lookupInSchemaBucket(bucketName, schema, null, localName3);
734
+ const noNamespace = lookupInSchemaBucket(bucketName, schema, null, localName4);
662
735
  if (noNamespace) return noNamespace;
663
736
  const sameSchemaNs = schema.targetNamespace || null;
664
737
  if (sameSchemaNs !== null) {
@@ -666,13 +739,13 @@ var UssXsdEngine = (() => {
666
739
  bucketName,
667
740
  schema,
668
741
  sameSchemaNs,
669
- localName3
742
+ localName4
670
743
  );
671
744
  if (hostNamespaceDecl) return hostNamespaceDecl;
672
745
  const importedSameNamespaceDecl = lookupInImportedSchemasForUnprefixed(
673
746
  bucketName,
674
747
  schema,
675
- localName3
748
+ localName4
676
749
  );
677
750
  if (importedSameNamespaceDecl) return importedSameNamespaceDecl;
678
751
  }
@@ -800,11 +873,6 @@ var UssXsdEngine = (() => {
800
873
 
801
874
  // src/parser/buildSchemaModel.js
802
875
  var UNSUPPORTED_NODE_FEATURES = /* @__PURE__ */ new Set([
803
- "key",
804
- "keyref",
805
- "unique",
806
- "any",
807
- "anyAttribute",
808
876
  "redefine",
809
877
  "notation"
810
878
  ]);
@@ -867,6 +935,9 @@ var UssXsdEngine = (() => {
867
935
  ...sourceSchema.externalRefs.imports || []
868
936
  );
869
937
  targetSchema.importedSchemas.push(...sourceSchema.importedSchemas || []);
938
+ targetSchema.identityConstraints.push(
939
+ ...sourceSchema.identityConstraints || []
940
+ );
870
941
  for (const feature of sourceSchema.usedFeatures || []) {
871
942
  targetSchema.usedFeatures.add(feature);
872
943
  }
@@ -919,17 +990,17 @@ var UssXsdEngine = (() => {
919
990
  }
920
991
  function locateNodeInSource(xsdText, lineStarts, node) {
921
992
  if (!xsdText || !node) return { line: null, column: null };
922
- const localName3 = node.localName;
993
+ const localName4 = node.localName;
923
994
  const name = node.getAttribute("name");
924
995
  const ref = node.getAttribute("ref");
925
996
  const base = node.getAttribute("base");
926
997
  const type = node.getAttribute("type");
927
998
  const candidates = [
928
- name ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\bname=(["'])${escapeRegExp(name)}\\1` : null,
929
- ref ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\bref=(["'])${escapeRegExp(ref)}\\1` : null,
930
- base ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\bbase=(["'])${escapeRegExp(base)}\\1` : null,
931
- type ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\btype=(["'])${escapeRegExp(type)}\\1` : null,
932
- `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b`
999
+ name ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bname=(["'])${escapeRegExp(name)}\\1` : null,
1000
+ ref ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bref=(["'])${escapeRegExp(ref)}\\1` : null,
1001
+ base ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bbase=(["'])${escapeRegExp(base)}\\1` : null,
1002
+ type ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\btype=(["'])${escapeRegExp(type)}\\1` : null,
1003
+ `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b`
933
1004
  ].filter(Boolean);
934
1005
  for (const pattern of candidates) {
935
1006
  const regex = new RegExp(pattern, "m");
@@ -952,9 +1023,9 @@ var UssXsdEngine = (() => {
952
1023
  return `${parentPath}/${kind}${qualifier}`;
953
1024
  }
954
1025
  function registerGlobal(schema, issues, bucketName, duplicateCode, decl) {
955
- const localName3 = stripNamespacePrefix(decl.name);
956
- if (!localName3) return;
957
- const key = makeLookupKey(decl.namespaceUri, localName3);
1026
+ const localName4 = stripNamespacePrefix(decl.name);
1027
+ if (!localName4) return;
1028
+ const key = makeLookupKey(decl.namespaceUri, localName4);
958
1029
  if (schema.globals[bucketName][key]) {
959
1030
  issues.push(
960
1031
  createIssue({
@@ -981,15 +1052,15 @@ var UssXsdEngine = (() => {
981
1052
  schema.unsupportedFeatures.push(feature);
982
1053
  }
983
1054
  function collectNodeDiagnostics(schema, issues, node, path, loc) {
984
- const localName3 = node.localName;
985
- schema.usedFeatures.add(localName3);
986
- if (UNSUPPORTED_NODE_FEATURES.has(localName3)) {
1055
+ const localName4 = node.localName;
1056
+ schema.usedFeatures.add(localName4);
1057
+ if (UNSUPPORTED_NODE_FEATURES.has(localName4)) {
987
1058
  collectUnsupportedFeature(schema, {
988
- feature: `xs:${localName3}`,
1059
+ feature: `xs:${localName4}`,
989
1060
  line: loc.line,
990
1061
  column: loc.column,
991
1062
  path,
992
- nodeKind: localName3,
1063
+ nodeKind: localName4,
993
1064
  name: node.getAttribute("name") || null
994
1065
  });
995
1066
  }
@@ -999,7 +1070,7 @@ var UssXsdEngine = (() => {
999
1070
  line: loc.line,
1000
1071
  column: loc.column,
1001
1072
  path,
1002
- nodeKind: localName3,
1073
+ nodeKind: localName4,
1003
1074
  name: node.getAttribute("name") || null
1004
1075
  });
1005
1076
  }
@@ -1009,47 +1080,47 @@ var UssXsdEngine = (() => {
1009
1080
  line: loc.line,
1010
1081
  column: loc.column,
1011
1082
  path,
1012
- nodeKind: localName3,
1083
+ nodeKind: localName4,
1013
1084
  name: node.getAttribute("name") || node.getAttribute("ref") || null
1014
1085
  });
1015
1086
  }
1016
- if ((localName3 === "element" || localName3 === "attribute") && node.hasAttribute("ref")) {
1087
+ if ((localName4 === "element" || localName4 === "attribute") && node.hasAttribute("ref")) {
1017
1088
  collectReference(schema, "refs", {
1018
1089
  refName: node.getAttribute("ref"),
1019
1090
  line: loc.line,
1020
1091
  column: loc.column,
1021
1092
  path,
1022
- nodeKind: localName3,
1093
+ nodeKind: localName4,
1023
1094
  name: node.getAttribute("name") || null
1024
1095
  });
1025
1096
  }
1026
- if ((localName3 === "extension" || localName3 === "restriction") && node.hasAttribute("base")) {
1097
+ if ((localName4 === "extension" || localName4 === "restriction") && node.hasAttribute("base")) {
1027
1098
  collectReference(schema, "baseTypes", {
1028
1099
  baseTypeName: node.getAttribute("base"),
1029
1100
  line: loc.line,
1030
1101
  column: loc.column,
1031
1102
  path,
1032
- nodeKind: localName3,
1103
+ nodeKind: localName4,
1033
1104
  name: node.getAttribute("name") || null
1034
1105
  });
1035
1106
  }
1036
- if (localName3 === "group" && node.hasAttribute("ref")) {
1107
+ if (localName4 === "group" && node.hasAttribute("ref")) {
1037
1108
  collectReference(schema, "groupRefs", {
1038
1109
  refName: node.getAttribute("ref"),
1039
1110
  line: loc.line,
1040
1111
  column: loc.column,
1041
1112
  path,
1042
- nodeKind: localName3,
1113
+ nodeKind: localName4,
1043
1114
  name: node.getAttribute("name") || null
1044
1115
  });
1045
1116
  }
1046
- if (localName3 === "attributeGroup" && node.hasAttribute("ref")) {
1117
+ if (localName4 === "attributeGroup" && node.hasAttribute("ref")) {
1047
1118
  collectReference(schema, "attributeGroupRefs", {
1048
1119
  refName: node.getAttribute("ref"),
1049
1120
  line: loc.line,
1050
1121
  column: loc.column,
1051
1122
  path,
1052
- nodeKind: localName3,
1123
+ nodeKind: localName4,
1053
1124
  name: node.getAttribute("name") || null
1054
1125
  });
1055
1126
  }
@@ -1065,13 +1136,13 @@ var UssXsdEngine = (() => {
1065
1136
  column: loc.column,
1066
1137
  path,
1067
1138
  source: "xsd",
1068
- nodeKind: localName3,
1139
+ nodeKind: localName4,
1069
1140
  name: node.getAttribute("name") || null,
1070
1141
  details: { minOccurs, maxOccurs }
1071
1142
  })
1072
1143
  );
1073
1144
  }
1074
- if ((localName3 === "element" || localName3 === "attribute") && node.hasAttribute("default") && node.hasAttribute("fixed")) {
1145
+ if ((localName4 === "element" || localName4 === "attribute") && node.hasAttribute("default") && node.hasAttribute("fixed")) {
1075
1146
  issues.push(
1076
1147
  createIssue({
1077
1148
  code: ISSUE_CODES.INVALID_DEFAULT_FIXED_COMBINATION,
@@ -1081,7 +1152,7 @@ var UssXsdEngine = (() => {
1081
1152
  column: loc.column,
1082
1153
  path,
1083
1154
  source: "xsd",
1084
- nodeKind: localName3,
1155
+ nodeKind: localName4,
1085
1156
  name: node.getAttribute("name") || node.getAttribute("ref") || null,
1086
1157
  details: {
1087
1158
  defaultValue: node.getAttribute("default"),
@@ -1162,11 +1233,11 @@ var UssXsdEngine = (() => {
1162
1233
  enumerations = parsed.enumerations;
1163
1234
  }
1164
1235
  const qName = node.getAttribute("name");
1165
- const namespaceUri3 = schema.targetNamespace || null;
1236
+ const namespaceUri4 = schema.targetNamespace || null;
1166
1237
  return createSimpleTypeDecl({
1167
1238
  name: qName ? parseQName(qName).localName : null,
1168
1239
  qName,
1169
- namespaceUri: namespaceUri3,
1240
+ namespaceUri: namespaceUri4,
1170
1241
  baseTypeName,
1171
1242
  facets,
1172
1243
  enumerations,
@@ -1191,11 +1262,11 @@ var UssXsdEngine = (() => {
1191
1262
  issues
1192
1263
  ) : null;
1193
1264
  const qName = node.getAttribute("name");
1194
- const namespaceUri3 = getDeclarationNamespaceUri(schema, node, "attribute");
1265
+ const namespaceUri4 = getDeclarationNamespaceUri(schema, node, "attribute");
1195
1266
  return createAttributeDecl({
1196
1267
  name: qName ? parseQName(qName).localName : null,
1197
1268
  qName,
1198
- namespaceUri: namespaceUri3,
1269
+ namespaceUri: namespaceUri4,
1199
1270
  typeName: node.getAttribute("type"),
1200
1271
  refName: node.getAttribute("ref"),
1201
1272
  inlineType,
@@ -1236,6 +1307,10 @@ var UssXsdEngine = (() => {
1236
1307
  issues
1237
1308
  )
1238
1309
  );
1310
+ } else if (child.localName === "anyAttribute") {
1311
+ attributes.push(
1312
+ parseAnyAttribute(child, xsdText, lineStarts, parentPath, schema, issues)
1313
+ );
1239
1314
  }
1240
1315
  }
1241
1316
  return attributes;
@@ -1272,11 +1347,26 @@ var UssXsdEngine = (() => {
1272
1347
  );
1273
1348
  }
1274
1349
  const qName = node.getAttribute("name");
1275
- const namespaceUri3 = getDeclarationNamespaceUri(schema, node, "element");
1350
+ const namespaceUri4 = getDeclarationNamespaceUri(schema, node, "element");
1351
+ const identityConstraints = children.filter(
1352
+ (child) => ["key", "keyref", "unique"].includes(child.localName)
1353
+ ).map(
1354
+ (child) => parseIdentityConstraint(
1355
+ child,
1356
+ xsdText,
1357
+ lineStarts,
1358
+ path,
1359
+ schema,
1360
+ issues,
1361
+ qName ? parseQName(qName).localName : null,
1362
+ namespaceUri4,
1363
+ path
1364
+ )
1365
+ );
1276
1366
  return createElementDecl({
1277
1367
  name: qName ? parseQName(qName).localName : null,
1278
1368
  qName,
1279
- namespaceUri: namespaceUri3,
1369
+ namespaceUri: namespaceUri4,
1280
1370
  typeName: node.getAttribute("type"),
1281
1371
  refName: node.getAttribute("ref"),
1282
1372
  inlineType,
@@ -1285,6 +1375,7 @@ var UssXsdEngine = (() => {
1285
1375
  defaultValue: node.getAttribute("default"),
1286
1376
  fixedValue: node.getAttribute("fixed"),
1287
1377
  nillable: node.getAttribute("nillable") === "true",
1378
+ identityConstraints,
1288
1379
  line: loc.line,
1289
1380
  column: loc.column,
1290
1381
  path
@@ -1303,20 +1394,101 @@ var UssXsdEngine = (() => {
1303
1394
  path
1304
1395
  });
1305
1396
  }
1397
+ function parseWildcardNamespace(namespaceStr) {
1398
+ if (!namespaceStr) return null;
1399
+ const trimmed = namespaceStr.trim();
1400
+ if (!trimmed) return null;
1401
+ if (trimmed.includes(" ")) {
1402
+ return trimmed.split(/\s+/).filter((ns) => ns);
1403
+ }
1404
+ return trimmed;
1405
+ }
1406
+ function parseNotNamespace(notNamespaceStr) {
1407
+ if (!notNamespaceStr) return [];
1408
+ const trimmed = notNamespaceStr.trim();
1409
+ if (!trimmed) return [];
1410
+ if (trimmed.includes(" ")) {
1411
+ return trimmed.split(/\s+/).filter((ns) => ns);
1412
+ }
1413
+ return [trimmed];
1414
+ }
1415
+ function parseNotQName(notQNameStr) {
1416
+ if (!notQNameStr) return [];
1417
+ const trimmed = notQNameStr.trim();
1418
+ if (!trimmed) return [];
1419
+ if (trimmed.includes(" ")) {
1420
+ return trimmed.split(/\s+/).filter((qn) => qn);
1421
+ }
1422
+ return [trimmed];
1423
+ }
1306
1424
  function parseAny(node, xsdText, lineStarts, parentPath, schema, issues) {
1307
1425
  const path = buildPath(parentPath, node);
1308
1426
  const loc = locateNodeInSource(xsdText, lineStarts, node);
1309
1427
  collectNodeDiagnostics(schema, issues, node, path, loc);
1310
1428
  return createAnyNode({
1311
- namespace: node.getAttribute("namespace"),
1429
+ namespace: parseWildcardNamespace(node.getAttribute("namespace")),
1312
1430
  processContents: node.getAttribute("processContents"),
1313
1431
  minOccurs: normalizeOccurs(node.getAttribute("minOccurs"), 1),
1314
1432
  maxOccurs: normalizeOccurs(node.getAttribute("maxOccurs"), 1),
1433
+ notNamespace: parseNotNamespace(node.getAttribute("notNamespace")),
1434
+ notQName: parseNotQName(node.getAttribute("notQName")),
1315
1435
  line: loc.line,
1316
1436
  column: loc.column,
1317
1437
  path
1318
1438
  });
1319
1439
  }
1440
+ function parseAnyAttribute(node, xsdText, lineStarts, parentPath, schema, issues) {
1441
+ const path = buildPath(parentPath, node);
1442
+ const loc = locateNodeInSource(xsdText, lineStarts, node);
1443
+ collectNodeDiagnostics(schema, issues, node, path, loc);
1444
+ return createAnyAttributeNode({
1445
+ namespace: parseWildcardNamespace(node.getAttribute("namespace")),
1446
+ processContents: node.getAttribute("processContents"),
1447
+ notNamespace: parseNotNamespace(node.getAttribute("notNamespace")),
1448
+ notQName: parseNotQName(node.getAttribute("notQName")),
1449
+ line: loc.line,
1450
+ column: loc.column,
1451
+ path
1452
+ });
1453
+ }
1454
+ function parseIdentityConstraint(node, xsdText, lineStarts, parentPath, schema, issues, ownerName, ownerNamespaceUri, ownerPath) {
1455
+ const path = buildPath(parentPath, node);
1456
+ const loc = locateNodeInSource(xsdText, lineStarts, node);
1457
+ collectNodeDiagnostics(schema, issues, node, path, loc);
1458
+ const selectorNode = elementChildren(node).find(
1459
+ (child) => child.localName === "selector"
1460
+ );
1461
+ const selector = selectorNode ? {
1462
+ xpath: selectorNode.getAttribute("xpath"),
1463
+ path: buildPath(path, selectorNode)
1464
+ } : null;
1465
+ const fields = elementChildren(node).filter((child) => child.localName === "field").map((child) => ({
1466
+ xpath: child.getAttribute("xpath"),
1467
+ line: locateNodeInSource(xsdText, lineStarts, child).line,
1468
+ column: locateNodeInSource(xsdText, lineStarts, child).column,
1469
+ path: buildPath(path, child)
1470
+ })).filter((field) => field.xpath != null);
1471
+ const qName = node.getAttribute("name");
1472
+ const name = qName ? parseQName(qName).localName : null;
1473
+ const namespaceUri4 = ownerNamespaceUri || schema.targetNamespace || null;
1474
+ const constraint = createIdentityConstraint({
1475
+ kind: node.localName,
1476
+ name,
1477
+ qName,
1478
+ namespaceUri: namespaceUri4,
1479
+ selector,
1480
+ fields,
1481
+ refer: node.getAttribute("refer"),
1482
+ ownerName,
1483
+ ownerNamespaceUri,
1484
+ ownerPath,
1485
+ line: loc.line,
1486
+ column: loc.column,
1487
+ path
1488
+ });
1489
+ schema.identityConstraints.push(constraint);
1490
+ return constraint;
1491
+ }
1320
1492
  function parseContentNode(node, xsdText, lineStarts, parentPath, schema, issues) {
1321
1493
  const path = buildPath(parentPath, node);
1322
1494
  const loc = locateNodeInSource(xsdText, lineStarts, node);
@@ -1463,6 +1635,22 @@ var UssXsdEngine = (() => {
1463
1635
  let derivation = { kind: null, baseTypeName: null };
1464
1636
  let contentModel = "complex";
1465
1637
  const children = elementChildren(node);
1638
+ const namespaceUri4 = schema.targetNamespace || null;
1639
+ const identityConstraints = children.filter(
1640
+ (child) => ["key", "keyref", "unique"].includes(child.localName)
1641
+ ).map(
1642
+ (child) => parseIdentityConstraint(
1643
+ child,
1644
+ xsdText,
1645
+ lineStarts,
1646
+ path,
1647
+ schema,
1648
+ issues,
1649
+ null,
1650
+ namespaceUri4,
1651
+ path
1652
+ )
1653
+ );
1466
1654
  const directContentNode = children.find(
1467
1655
  (child) => ["sequence", "choice", "all", "group", "element", "any"].includes(
1468
1656
  child.localName
@@ -1522,17 +1710,17 @@ var UssXsdEngine = (() => {
1522
1710
  );
1523
1711
  }
1524
1712
  const qName = node.getAttribute("name");
1525
- const namespaceUri3 = schema.targetNamespace || null;
1526
1713
  return createComplexTypeDecl({
1527
1714
  name: qName ? parseQName(qName).localName : null,
1528
1715
  qName,
1529
- namespaceUri: namespaceUri3,
1716
+ namespaceUri: namespaceUri4,
1530
1717
  content,
1531
1718
  attributes,
1532
1719
  derivation,
1533
1720
  contentModel,
1534
1721
  mixed: node.getAttribute("mixed") === "true",
1535
1722
  abstract: node.getAttribute("abstract") === "true",
1723
+ identityConstraints,
1536
1724
  line: loc.line,
1537
1725
  column: loc.column,
1538
1726
  path
@@ -1546,11 +1734,11 @@ var UssXsdEngine = (() => {
1546
1734
  (child) => ["sequence", "choice", "all"].includes(child.localName)
1547
1735
  );
1548
1736
  const qName = node.getAttribute("name");
1549
- const namespaceUri3 = schema.targetNamespace || null;
1737
+ const namespaceUri4 = schema.targetNamespace || null;
1550
1738
  return createGroupDecl({
1551
1739
  name: qName ? parseQName(qName).localName : null,
1552
1740
  qName,
1553
- namespaceUri: namespaceUri3,
1741
+ namespaceUri: namespaceUri4,
1554
1742
  content: contentNode ? parseContentNode(contentNode, xsdText, lineStarts, path, schema, issues) : null,
1555
1743
  line: loc.line,
1556
1744
  column: loc.column,
@@ -1572,11 +1760,11 @@ var UssXsdEngine = (() => {
1572
1760
  issues
1573
1761
  );
1574
1762
  const qName = node.getAttribute("name");
1575
- const namespaceUri3 = schema.targetNamespace || null;
1763
+ const namespaceUri4 = schema.targetNamespace || null;
1576
1764
  return createAttributeGroupDecl({
1577
1765
  name: qName ? parseQName(qName).localName : null,
1578
1766
  qName,
1579
- namespaceUri: namespaceUri3,
1767
+ namespaceUri: namespaceUri4,
1580
1768
  attributes,
1581
1769
  line: loc.line,
1582
1770
  column: loc.column,
@@ -1680,24 +1868,24 @@ var UssXsdEngine = (() => {
1680
1868
  }
1681
1869
  }
1682
1870
  if (ref?.kind === "import" && ref.namespace) {
1683
- const namespaceMatches = entries.filter((entry) => {
1871
+ const namespaceMatches2 = entries.filter((entry) => {
1684
1872
  const declaredTargetNamespace = getDeclaredTargetNamespaceFromText(
1685
1873
  entry.text
1686
1874
  );
1687
1875
  return (declaredTargetNamespace || null) === (ref.namespace || null);
1688
1876
  });
1689
- if (namespaceMatches.length === 1) {
1877
+ if (namespaceMatches2.length === 1) {
1690
1878
  return {
1691
1879
  kind: "namespace",
1692
- entry: namespaceMatches[0],
1693
- matches: namespaceMatches
1880
+ entry: namespaceMatches2[0],
1881
+ matches: namespaceMatches2
1694
1882
  };
1695
1883
  }
1696
- if (namespaceMatches.length > 1) {
1884
+ if (namespaceMatches2.length > 1) {
1697
1885
  return {
1698
1886
  kind: "ambiguous-namespace",
1699
1887
  entry: null,
1700
- matches: namespaceMatches
1888
+ matches: namespaceMatches2
1701
1889
  };
1702
1890
  }
1703
1891
  }
@@ -2314,6 +2502,115 @@ var UssXsdEngine = (() => {
2314
2502
  }
2315
2503
  }
2316
2504
  }
2505
+ function checkWildcardRestriction(schema, derivedType, baseType, issues) {
2506
+ const derivedContent = getEffectiveContent(schema, derivedType);
2507
+ const baseContent = getEffectiveContent(schema, baseType);
2508
+ const derivedWildcards = [];
2509
+ const baseWildcards = [];
2510
+ function collectWildcards(node, arr) {
2511
+ if (!node) return;
2512
+ if (node.kind === "any") {
2513
+ arr.push(node);
2514
+ return;
2515
+ }
2516
+ if (node.children) {
2517
+ for (const child of asArray(node.children)) {
2518
+ collectWildcards(child, arr);
2519
+ }
2520
+ }
2521
+ }
2522
+ collectWildcards(derivedContent, derivedWildcards);
2523
+ collectWildcards(baseContent, baseWildcards);
2524
+ if (derivedWildcards.length > 0 && baseWildcards.length === 0) {
2525
+ issues.push(
2526
+ buildRestrictionIssue(
2527
+ "XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
2528
+ `Restricted type introduces wildcard elements that base type does not have.`,
2529
+ derivedType
2530
+ )
2531
+ );
2532
+ }
2533
+ const derivedAttrs = asArray(getEffectiveAttributes(schema, derivedType));
2534
+ const baseAttrs = asArray(getEffectiveAttributes(schema, baseType));
2535
+ const derivedHasAnyAttribute = derivedAttrs.some((a) => a?.kind === "anyAttribute");
2536
+ const baseHasAnyAttribute = baseAttrs.some((a) => a?.kind === "anyAttribute");
2537
+ if (derivedHasAnyAttribute && !baseHasAnyAttribute) {
2538
+ issues.push(
2539
+ buildRestrictionIssue(
2540
+ "XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
2541
+ `Restricted type introduces anyAttribute that base type does not have.`,
2542
+ derivedType
2543
+ )
2544
+ );
2545
+ }
2546
+ }
2547
+ function checkOccurrenceCompatibility(derived, base, name) {
2548
+ const dMin = typeof derived.minOccurs === "number" ? derived.minOccurs : 1;
2549
+ const bMin = typeof base.minOccurs === "number" ? base.minOccurs : 1;
2550
+ const dMax = maxToNumber(derived.maxOccurs ?? 1);
2551
+ const bMax = maxToNumber(base.maxOccurs ?? 1);
2552
+ return dMin >= bMin && dMax <= bMax;
2553
+ }
2554
+ function checkComplexContentRestriction(schema, derivedType, baseType, issues) {
2555
+ const derivedContent = getEffectiveContent(schema, derivedType);
2556
+ const baseContent = getEffectiveContent(schema, baseType);
2557
+ if (!derivedContent || !baseContent) return;
2558
+ const derivedFlat = flattenContent(derivedContent, []);
2559
+ const baseFlat = flattenContent(baseContent, []);
2560
+ const baseMap = new Map(baseFlat.map((item) => [item.name, item]));
2561
+ for (const item of derivedFlat) {
2562
+ const baseItem = baseMap.get(item.name);
2563
+ if (!baseItem) {
2564
+ issues.push(
2565
+ buildRestrictionIssue(
2566
+ "XSD_RESTRICTION_NOT_SUBSET",
2567
+ `Restricted type contains element '${item.name}' not in base type.`,
2568
+ item
2569
+ )
2570
+ );
2571
+ continue;
2572
+ }
2573
+ if (!checkOccurrenceCompatibility(item, baseItem, item.name)) {
2574
+ issues.push(
2575
+ buildRestrictionIssue(
2576
+ "XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE",
2577
+ `Restricted type has incompatible occurrence constraints for '${item.name}'.`,
2578
+ item
2579
+ )
2580
+ );
2581
+ }
2582
+ }
2583
+ }
2584
+ function checkSimpleContentRestriction(schema, derivedType, baseType, issues) {
2585
+ if (baseType.contentModel !== "simple") {
2586
+ issues.push(
2587
+ buildRestrictionIssue(
2588
+ "XSD_RESTRICTION_NOT_SUBSET",
2589
+ `SimpleContent restriction requires base type to have simple content.`,
2590
+ derivedType
2591
+ )
2592
+ );
2593
+ }
2594
+ const derivedAttrs = asArray(getEffectiveAttributes(schema, derivedType));
2595
+ const baseAttrs = asArray(getEffectiveAttributes(schema, baseType));
2596
+ const baseAttrMap = new Map(
2597
+ baseAttrs.filter((attr) => attr?.kind === "attribute").map((attr) => [localDeclName(attr), attr])
2598
+ );
2599
+ for (const attr of derivedAttrs) {
2600
+ if (attr?.kind !== "attribute") continue;
2601
+ const name = localDeclName(attr);
2602
+ const baseAttr = baseAttrMap.get(name);
2603
+ if (!baseAttr && !baseAttrs.some((a) => a?.kind === "anyAttribute")) {
2604
+ issues.push(
2605
+ buildRestrictionIssue(
2606
+ "XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE",
2607
+ `SimpleContent restricted type adds attribute '${name}' not in base type.`,
2608
+ attr
2609
+ )
2610
+ );
2611
+ }
2612
+ }
2613
+ }
2317
2614
  function runRestrictionDiagnostics(schema) {
2318
2615
  const issues = [];
2319
2616
  for (const complexType of Object.values(schema.globals.complexTypes || {})) {
@@ -2323,6 +2620,12 @@ var UssXsdEngine = (() => {
2323
2620
  if (!baseType) continue;
2324
2621
  checkRestrictedContentSubset(schema, complexType, baseType, issues);
2325
2622
  checkRestrictedAttributes(schema, complexType, baseType, issues);
2623
+ checkWildcardRestriction(schema, complexType, baseType, issues);
2624
+ if (complexType.contentModel === "complex" && baseType.contentModel === "complex") {
2625
+ checkComplexContentRestriction(schema, complexType, baseType, issues);
2626
+ } else if (complexType.contentModel === "simple" && baseType.contentModel === "simple") {
2627
+ checkSimpleContentRestriction(schema, complexType, baseType, issues);
2628
+ }
2326
2629
  }
2327
2630
  return issues;
2328
2631
  }
@@ -2359,6 +2662,188 @@ var UssXsdEngine = (() => {
2359
2662
  return issues;
2360
2663
  }
2361
2664
 
2665
+ // src/diagnostics/schemaIdentityConstraintDiagnostics.js
2666
+ function isValidConstraintXPath(xpath) {
2667
+ if (!xpath || typeof xpath !== "string") return false;
2668
+ const trimmed = xpath.trim();
2669
+ if (!trimmed) return false;
2670
+ let normalized = trimmed;
2671
+ if (trimmed.startsWith("./")) {
2672
+ if (trimmed.startsWith(".//")) normalized = trimmed.slice(1);
2673
+ else normalized = trimmed.slice(2);
2674
+ }
2675
+ if (normalized.startsWith("/") && !normalized.startsWith("//")) return false;
2676
+ if (normalized.includes("///")) return false;
2677
+ let segments = normalized.split(
2678
+ /\/+/
2679
+ );
2680
+ if (normalized.startsWith("//")) segments = segments.slice(1);
2681
+ if (normalized.endsWith("//")) segments = segments.slice(0, -1);
2682
+ if (segments.some((segment) => segment.length === 0)) return false;
2683
+ for (const segment of segments) {
2684
+ if (segment === ".") continue;
2685
+ if (segment === "*") continue;
2686
+ if (segment.startsWith("@")) {
2687
+ const attrName = segment.slice(1);
2688
+ if (!/^[A-Za-z_][\w.-]*$/.test(attrName)) return false;
2689
+ continue;
2690
+ }
2691
+ const parsed = parseQName(segment);
2692
+ if (!parsed.localName) return false;
2693
+ }
2694
+ return true;
2695
+ }
2696
+ function getConstraintKey(constraint) {
2697
+ return `${constraint.ownerPath || ""}::${constraint.name || ""}`;
2698
+ }
2699
+ function findReferencedKey(schema, refer) {
2700
+ if (!refer) return null;
2701
+ const referName = parseQName(refer).localName;
2702
+ return schema.identityConstraints.find(
2703
+ (constraint) => constraint.kind === "key" && constraint.name === referName
2704
+ );
2705
+ }
2706
+ function runIdentityConstraintDiagnostics(schema) {
2707
+ const issues = [];
2708
+ const seenNames = /* @__PURE__ */ new Set();
2709
+ for (const constraint of schema.identityConstraints || []) {
2710
+ const key = getConstraintKey(constraint);
2711
+ if (seenNames.has(key)) {
2712
+ issues.push(
2713
+ createIssue({
2714
+ code: ISSUE_CODES.DUPLICATE_CONSTRAINT_NAME,
2715
+ severity: "error",
2716
+ message: `Duplicate identity constraint name '${constraint.name}' in the same scope.`,
2717
+ line: constraint.line,
2718
+ column: constraint.column,
2719
+ path: constraint.path,
2720
+ source: "xsd",
2721
+ nodeKind: constraint.kind,
2722
+ name: constraint.name,
2723
+ details: {
2724
+ ownerPath: constraint.ownerPath,
2725
+ ownerName: constraint.ownerName
2726
+ }
2727
+ })
2728
+ );
2729
+ } else {
2730
+ seenNames.add(key);
2731
+ }
2732
+ if (!constraint.selector || !constraint.selector.xpath) {
2733
+ issues.push(
2734
+ createIssue({
2735
+ code: ISSUE_CODES.INVALID_CONSTRAINT_SELECTOR,
2736
+ severity: "error",
2737
+ message: `Identity constraint '${constraint.name || constraint.kind}' is missing a selector xpath.`,
2738
+ line: constraint.line,
2739
+ column: constraint.column,
2740
+ path: constraint.path,
2741
+ source: "xsd",
2742
+ nodeKind: constraint.kind,
2743
+ name: constraint.name,
2744
+ details: {
2745
+ ownerPath: constraint.ownerPath,
2746
+ ownerName: constraint.ownerName
2747
+ }
2748
+ })
2749
+ );
2750
+ } else if (!isValidConstraintXPath(constraint.selector.xpath)) {
2751
+ issues.push(
2752
+ createIssue({
2753
+ code: ISSUE_CODES.INVALID_CONSTRAINT_SELECTOR,
2754
+ severity: "error",
2755
+ message: `Invalid selector xpath '${constraint.selector.xpath}'.`,
2756
+ line: constraint.line,
2757
+ column: constraint.column,
2758
+ path: constraint.selector.path,
2759
+ source: "xsd",
2760
+ nodeKind: constraint.kind,
2761
+ name: constraint.name,
2762
+ details: {
2763
+ selector: constraint.selector.xpath,
2764
+ ownerPath: constraint.ownerPath
2765
+ }
2766
+ })
2767
+ );
2768
+ }
2769
+ if (!constraint.fields?.length) {
2770
+ issues.push(
2771
+ createIssue({
2772
+ code: ISSUE_CODES.INVALID_CONSTRAINT_FIELD,
2773
+ severity: "error",
2774
+ message: `Identity constraint '${constraint.name || constraint.kind}' must declare at least one field.`,
2775
+ line: constraint.line,
2776
+ column: constraint.column,
2777
+ path: constraint.path,
2778
+ source: "xsd",
2779
+ nodeKind: constraint.kind,
2780
+ name: constraint.name,
2781
+ details: { ownerPath: constraint.ownerPath }
2782
+ })
2783
+ );
2784
+ } else {
2785
+ for (const field of constraint.fields) {
2786
+ if (!field.xpath || !isValidConstraintXPath(field.xpath)) {
2787
+ issues.push(
2788
+ createIssue({
2789
+ code: ISSUE_CODES.INVALID_CONSTRAINT_FIELD,
2790
+ severity: "error",
2791
+ message: `Invalid field xpath '${field.xpath}'.`,
2792
+ line: field.line,
2793
+ column: field.column,
2794
+ path: field.path,
2795
+ source: "xsd",
2796
+ nodeKind: constraint.kind,
2797
+ name: constraint.name,
2798
+ details: {
2799
+ field: field.xpath,
2800
+ ownerPath: constraint.ownerPath
2801
+ }
2802
+ })
2803
+ );
2804
+ }
2805
+ }
2806
+ }
2807
+ if (constraint.kind === "keyref") {
2808
+ if (!constraint.refer) {
2809
+ issues.push(
2810
+ createIssue({
2811
+ code: ISSUE_CODES.UNKNOWN_KEY_REFERENCE,
2812
+ severity: "error",
2813
+ message: `xs:keyref '${constraint.name || "unnamed"}' is missing a refer attribute.`,
2814
+ line: constraint.line,
2815
+ column: constraint.column,
2816
+ path: constraint.path,
2817
+ source: "xsd",
2818
+ nodeKind: constraint.kind,
2819
+ name: constraint.name,
2820
+ details: { ownerPath: constraint.ownerPath }
2821
+ })
2822
+ );
2823
+ } else if (!findReferencedKey(schema, constraint.refer)) {
2824
+ issues.push(
2825
+ createIssue({
2826
+ code: ISSUE_CODES.UNKNOWN_KEY_REFERENCE,
2827
+ severity: "error",
2828
+ message: `xs:keyref refers to unknown key '${constraint.refer}'.`,
2829
+ line: constraint.line,
2830
+ column: constraint.column,
2831
+ path: constraint.path,
2832
+ source: "xsd",
2833
+ nodeKind: constraint.kind,
2834
+ name: constraint.name,
2835
+ details: {
2836
+ refer: constraint.refer,
2837
+ ownerPath: constraint.ownerPath
2838
+ }
2839
+ })
2840
+ );
2841
+ }
2842
+ }
2843
+ }
2844
+ return issues;
2845
+ }
2846
+
2362
2847
  // src/diagnostics/schemaImportDiagnostics.js
2363
2848
  function normalizeSchemaPath2(value) {
2364
2849
  if (!value || typeof value !== "string") return null;
@@ -2467,6 +2952,130 @@ var UssXsdEngine = (() => {
2467
2952
  return issues;
2468
2953
  }
2469
2954
 
2955
+ // src/diagnostics/schemaWildcardDiagnostics.js
2956
+ function validateWildcardNamespace(namespace, path) {
2957
+ if (!namespace) return null;
2958
+ const trimmed = namespace.trim();
2959
+ if (!trimmed) return null;
2960
+ const parts = trimmed.split(/\s+/);
2961
+ for (const part of parts) {
2962
+ if (part === "##any" || part === "##other" || part === "##targetNamespace") {
2963
+ continue;
2964
+ }
2965
+ if (!part.includes(":") && part !== "") {
2966
+ return createIssue({
2967
+ code: "INVALID_WILDCARD_NAMESPACE",
2968
+ severity: "warning",
2969
+ message: `Invalid namespace in wildcard constraint: '${part}'. Expected ##any, ##other, ##targetNamespace, or a valid namespace URI.`,
2970
+ path
2971
+ });
2972
+ }
2973
+ }
2974
+ return null;
2975
+ }
2976
+ function validateProcessContents(processContents, path) {
2977
+ if (!processContents) return null;
2978
+ const trimmed = processContents.trim();
2979
+ if (trimmed === "strict" || trimmed === "lax" || trimmed === "skip") {
2980
+ return null;
2981
+ }
2982
+ return createIssue({
2983
+ code: "INVALID_PROCESS_CONTENTS",
2984
+ severity: "error",
2985
+ message: `Invalid processContents value: '${processContents}'. Must be 'strict', 'lax', or 'skip'.`,
2986
+ path
2987
+ });
2988
+ }
2989
+ function validateSingleWildcard(wildcardNode, nodeName) {
2990
+ const issues = [];
2991
+ const nsIssue = validateWildcardNamespace(wildcardNode.namespace, wildcardNode.path);
2992
+ if (nsIssue) {
2993
+ issues.push(nsIssue);
2994
+ }
2995
+ const pcIssue = validateProcessContents(wildcardNode.processContents, wildcardNode.path);
2996
+ if (pcIssue) {
2997
+ issues.push(pcIssue);
2998
+ }
2999
+ if (wildcardNode.notNamespace && wildcardNode.notNamespace.length > 0) {
3000
+ if (wildcardNode.namespace !== "##other" && wildcardNode.namespace !== "##targetNamespace") {
3001
+ issues.push(
3002
+ createIssue({
3003
+ code: "INVALID_NOT_NAMESPACE_USAGE",
3004
+ severity: "warning",
3005
+ message: `notNamespace is only meaningful with ##other or ##targetNamespace namespace constraint.`,
3006
+ path: wildcardNode.path
3007
+ })
3008
+ );
3009
+ }
3010
+ }
3011
+ if (wildcardNode.notQName && wildcardNode.notQName.length > 0) {
3012
+ for (const qname of wildcardNode.notQName) {
3013
+ if (!qname || qname.trim() === "") {
3014
+ issues.push(
3015
+ createIssue({
3016
+ code: "INVALID_NOT_QNAME",
3017
+ severity: "warning",
3018
+ message: `Empty QName in notQName constraint.`,
3019
+ path: wildcardNode.path
3020
+ })
3021
+ );
3022
+ break;
3023
+ }
3024
+ }
3025
+ }
3026
+ return issues;
3027
+ }
3028
+ function findWildcardsInContent(node, wildcards) {
3029
+ if (!node) return;
3030
+ if (node.kind === "any" || node.kind === "anyAttribute") {
3031
+ wildcards.push(node);
3032
+ return;
3033
+ }
3034
+ if (node.children && Array.isArray(node.children)) {
3035
+ for (const child of node.children) {
3036
+ findWildcardsInContent(child, wildcards);
3037
+ }
3038
+ }
3039
+ }
3040
+ function findWildcardsInAttributes(attributes, wildcards) {
3041
+ if (!attributes || !Array.isArray(attributes)) return;
3042
+ for (const attr of attributes) {
3043
+ if (attr.kind === "anyAttribute") {
3044
+ wildcards.push(attr);
3045
+ }
3046
+ }
3047
+ }
3048
+ function runWildcardDiagnostics(schema) {
3049
+ const issues = [];
3050
+ const wildcards = [];
3051
+ for (const elem of Object.values(schema.globals.elements || {})) {
3052
+ if (elem.inlineType?.content) {
3053
+ findWildcardsInContent(elem.inlineType.content, wildcards);
3054
+ }
3055
+ if (elem.inlineType?.attributes) {
3056
+ findWildcardsInAttributes(elem.inlineType.attributes, wildcards);
3057
+ }
3058
+ }
3059
+ for (const complexType of Object.values(schema.globals.complexTypes || {})) {
3060
+ if (complexType.content) {
3061
+ findWildcardsInContent(complexType.content, wildcards);
3062
+ }
3063
+ if (complexType.attributes) {
3064
+ findWildcardsInAttributes(complexType.attributes, wildcards);
3065
+ }
3066
+ }
3067
+ for (const group of Object.values(schema.globals.groups || {})) {
3068
+ if (group.content) {
3069
+ findWildcardsInContent(group.content, wildcards);
3070
+ }
3071
+ }
3072
+ for (const wildcard of wildcards) {
3073
+ const wildcardIssues = validateSingleWildcard(wildcard, wildcard.kind);
3074
+ issues.push(...wildcardIssues);
3075
+ }
3076
+ return issues;
3077
+ }
3078
+
2470
3079
  // src/diagnostics/schemaDiagnostics.js
2471
3080
  function buildStats(schema) {
2472
3081
  return {
@@ -2494,11 +3103,14 @@ var UssXsdEngine = (() => {
2494
3103
  "element",
2495
3104
  "extension",
2496
3105
  "group",
3106
+ "key",
3107
+ "keyref",
2497
3108
  "restriction",
2498
3109
  "schema",
2499
3110
  "sequence",
2500
3111
  "simpleContent",
2501
- "simpleType"
3112
+ "simpleType",
3113
+ "unique"
2502
3114
  ].includes(name)
2503
3115
  ).map((name) => `xs:${name}`)
2504
3116
  );
@@ -2635,7 +3247,11 @@ var UssXsdEngine = (() => {
2635
3247
  checkMissingBaseTypes(schema, issues);
2636
3248
  checkUnknownGroups(schema, issues);
2637
3249
  checkUnknownAttributeGroups(schema, issues);
3250
+ const identityIssues = runIdentityConstraintDiagnostics(schema);
3251
+ issues.push(...identityIssues);
2638
3252
  emitUnsupportedFeatureWarnings(schema, issues, options);
3253
+ const wildcardIssues = runWildcardDiagnostics(schema);
3254
+ issues.push(...wildcardIssues);
2639
3255
  const facetIssues = runFacetDiagnostics(schema, options);
2640
3256
  issues.push(...facetIssues);
2641
3257
  const restrictionIssues = runRestrictionDiagnostics(schema);
@@ -2656,7 +3272,7 @@ var UssXsdEngine = (() => {
2656
3272
  }
2657
3273
 
2658
3274
  // src/version.js
2659
- var ENGINE_VERSION = "v0.1.1";
3275
+ var ENGINE_VERSION = "v0.2.1";
2660
3276
 
2661
3277
  // src/utils/result.js
2662
3278
  function summarizeIssues(issues = []) {
@@ -2722,7 +3338,7 @@ var UssXsdEngine = (() => {
2722
3338
  refName = null,
2723
3339
  baseTypeName = null,
2724
3340
  derivation = null,
2725
- namespaceUri: namespaceUri3 = null,
3341
+ namespaceUri: namespaceUri4 = null,
2726
3342
  minOccurs = 1,
2727
3343
  maxOccurs = 1,
2728
3344
  use = null,
@@ -2739,7 +3355,7 @@ var UssXsdEngine = (() => {
2739
3355
  refName,
2740
3356
  baseTypeName,
2741
3357
  derivation,
2742
- namespaceUri: namespaceUri3,
3358
+ namespaceUri: namespaceUri4,
2743
3359
  minOccurs,
2744
3360
  maxOccurs,
2745
3361
  use,
@@ -2751,9 +3367,9 @@ var UssXsdEngine = (() => {
2751
3367
  }
2752
3368
 
2753
3369
  // src/tree/extractTree.js
2754
- function buildQualifiedLabel(name, namespaceUri3) {
3370
+ function buildQualifiedLabel(name, namespaceUri4) {
2755
3371
  if (!name) return name;
2756
- return namespaceUri3 ? `{${namespaceUri3}} ${name}` : name;
3372
+ return namespaceUri4 ? `{${namespaceUri4}} ${name}` : name;
2757
3373
  }
2758
3374
  function asArray2(value) {
2759
3375
  return Array.isArray(value) ? value : [];
@@ -3394,8 +4010,8 @@ var UssXsdEngine = (() => {
3394
4010
  Object.assign(target, source);
3395
4011
  }
3396
4012
  function qualifiedElementName(schema, elementDecl, state, isRoot = false) {
3397
- const localName3 = elementDecl.name || elementDecl.refName || "element";
3398
- const bare = localName3.includes(":") ? localName3.split(":")[1] : localName3;
4013
+ const localName4 = elementDecl.name || elementDecl.refName || "element";
4014
+ const bare = localName4.includes(":") ? localName4.split(":")[1] : localName4;
3399
4015
  const ns = elementDecl.namespaceUri;
3400
4016
  if (!ns) return bare;
3401
4017
  const prefix = state.nsContext.getPrefix(ns);
@@ -3544,6 +4160,24 @@ var UssXsdEngine = (() => {
3544
4160
  function buildComplexTypeContent(schema, complexTypeDecl, options, state) {
3545
4161
  const content = getEffectiveContent(schema, complexTypeDecl);
3546
4162
  const attributes = getEffectiveAttributes(schema, complexTypeDecl);
4163
+ if (state.currentDepth >= options.maxDepth) {
4164
+ return {
4165
+ attributes: buildAttributesObject(schema, attributes, options, state),
4166
+ children: []
4167
+ };
4168
+ }
4169
+ const typeKey = complexTypeDecl.name || complexTypeDecl.qName;
4170
+ if (typeKey && state.visitedTypes.has(typeKey)) {
4171
+ return {
4172
+ attributes: buildAttributesObject(schema, attributes, options, state),
4173
+ children: []
4174
+ };
4175
+ }
4176
+ if (typeKey) {
4177
+ state.visitedTypes.add(typeKey);
4178
+ }
4179
+ const previousDepth = state.currentDepth;
4180
+ state.currentDepth += 1;
3547
4181
  let children = content ? buildNodesFromContent(schema, content, options, state) : [];
3548
4182
  if (options.mode === "minimal" && children.length === 0 && content) {
3549
4183
  children = buildRepresentativeNodesFromContent(
@@ -3553,6 +4187,10 @@ var UssXsdEngine = (() => {
3553
4187
  state
3554
4188
  );
3555
4189
  }
4190
+ state.currentDepth = previousDepth;
4191
+ if (typeKey) {
4192
+ state.visitedTypes.delete(typeKey);
4193
+ }
3556
4194
  return {
3557
4195
  attributes: buildAttributesObject(schema, attributes, options, state),
3558
4196
  children
@@ -3631,7 +4269,10 @@ var UssXsdEngine = (() => {
3631
4269
  function generateXmlFromSchema(schema, options = {}, helpers = {}) {
3632
4270
  const normalizedOptions = {
3633
4271
  mode: options.mode === "full" ? "full" : "minimal",
3634
- includeOptionalAttributes: options.includeOptionalAttributes === true
4272
+ includeOptionalAttributes: options.includeOptionalAttributes === true,
4273
+ maxDepth: options.maxDepth ?? 3,
4274
+ maxChoiceBranches: options.maxChoiceBranches ?? 1,
4275
+ expandRepeatingElements: options.expandRepeatingElements ?? 2
3635
4276
  };
3636
4277
  const root = selectRoot(schema, options);
3637
4278
  if (!root) {
@@ -3644,7 +4285,9 @@ var UssXsdEngine = (() => {
3644
4285
  const state = {
3645
4286
  resolveAttributeGroup: helpers.resolveAttributeGroup,
3646
4287
  targetPrefix: options.targetPrefix || "tns",
3647
- nsContext
4288
+ nsContext,
4289
+ visitedTypes: /* @__PURE__ */ new Set(),
4290
+ currentDepth: 0
3648
4291
  };
3649
4292
  const [rootNode] = buildElementInstances(
3650
4293
  schema,
@@ -3747,6 +4390,80 @@ ${writeNode(rootNode, 0)}`;
3747
4390
  });
3748
4391
  }
3749
4392
 
4393
+ // src/validation/wildcardValidator.js
4394
+ function namespaceMatches(elementNamespace, wildcardNamespace, targetNamespace) {
4395
+ if (!wildcardNamespace) return true;
4396
+ if (wildcardNamespace === "##any") return true;
4397
+ if (wildcardNamespace === "##targetNamespace") {
4398
+ return elementNamespace === targetNamespace;
4399
+ }
4400
+ if (wildcardNamespace === "##other") {
4401
+ return elementNamespace !== targetNamespace;
4402
+ }
4403
+ if (Array.isArray(wildcardNamespace)) {
4404
+ return wildcardNamespace.includes(elementNamespace);
4405
+ }
4406
+ return elementNamespace === wildcardNamespace;
4407
+ }
4408
+ function isExcludedByNotNamespace(elementNamespace, notNamespace) {
4409
+ if (!notNamespace || notNamespace.length === 0) return false;
4410
+ return notNamespace.includes(elementNamespace);
4411
+ }
4412
+ function isExcludedByNotQName(qName, notQName) {
4413
+ if (!notQName || notQName.length === 0) return false;
4414
+ return notQName.includes(qName);
4415
+ }
4416
+ function buildQName(localName4, namespaceUri4) {
4417
+ if (!namespaceUri4 || namespaceUri4 === "") {
4418
+ return localName4;
4419
+ }
4420
+ return `{${namespaceUri4}}${localName4}`;
4421
+ }
4422
+ function elementMatchesWildcard(elementLocalName, elementNamespace, wildcardNode, targetNamespace) {
4423
+ if (!wildcardNode || wildcardNode.kind !== "any") {
4424
+ return false;
4425
+ }
4426
+ if (!namespaceMatches(elementNamespace, wildcardNode.namespace, targetNamespace)) {
4427
+ return false;
4428
+ }
4429
+ if (isExcludedByNotNamespace(elementNamespace, wildcardNode.notNamespace)) {
4430
+ return false;
4431
+ }
4432
+ const qName = buildQName(elementLocalName, elementNamespace);
4433
+ if (isExcludedByNotQName(qName, wildcardNode.notQName)) {
4434
+ return false;
4435
+ }
4436
+ return true;
4437
+ }
4438
+ function attributeMatchesWildcard(attrLocalName, attrNamespace, wildcardNode, targetNamespace) {
4439
+ if (!wildcardNode || wildcardNode.kind !== "anyAttribute") {
4440
+ return false;
4441
+ }
4442
+ if (!namespaceMatches(attrNamespace, wildcardNode.namespace, targetNamespace)) {
4443
+ return false;
4444
+ }
4445
+ if (isExcludedByNotNamespace(attrNamespace, wildcardNode.notNamespace)) {
4446
+ return false;
4447
+ }
4448
+ const qName = buildQName(attrLocalName, attrNamespace);
4449
+ if (isExcludedByNotQName(qName, wildcardNode.notQName)) {
4450
+ return false;
4451
+ }
4452
+ return true;
4453
+ }
4454
+ function normalizeProcessContents(processContents) {
4455
+ if (processContents === "lax" || processContents === "skip") {
4456
+ return processContents;
4457
+ }
4458
+ return "strict";
4459
+ }
4460
+ function isStrictWildcardValidation(processContents) {
4461
+ return normalizeProcessContents(processContents) === "strict";
4462
+ }
4463
+ function shouldSkipWildcardValidation(processContents) {
4464
+ return normalizeProcessContents(processContents) === "skip";
4465
+ }
4466
+
3750
4467
  // src/validation/structureValidator.js
3751
4468
  function elementChildren2(xmlNode) {
3752
4469
  return Array.from(xmlNode?.children || []).filter((child) => child.nodeType === 1);
@@ -3816,6 +4533,7 @@ ${writeNode(rootNode, 0)}`;
3816
4533
  function validateAttributes(xmlNode, attributes, context) {
3817
4534
  const { schema, createIssue: createIssue2, ISSUE_CODES: ISSUE_CODES2, issues, pathParts, validateAttributeValue: validateAttributeValue2 } = context;
3818
4535
  const allowed = /* @__PURE__ */ new Map();
4536
+ let anyAttributeWildcard = null;
3819
4537
  for (const attr of attributes || []) {
3820
4538
  if (!attr) continue;
3821
4539
  if (attr.kind === "attribute") {
@@ -3827,6 +4545,8 @@ ${writeNode(rootNode, 0)}`;
3827
4545
  const group = context.resolveAttributeGroup?.(attr.refName);
3828
4546
  if (!group) continue;
3829
4547
  validateAttributes(xmlNode, group.attributes || [], context);
4548
+ } else if (attr.kind === "anyAttribute") {
4549
+ anyAttributeWildcard = attr;
3830
4550
  }
3831
4551
  }
3832
4552
  for (const attrDecl of allowed.values()) {
@@ -3872,6 +4592,15 @@ ${writeNode(rootNode, 0)}`;
3872
4592
  continue;
3873
4593
  }
3874
4594
  if (!allowed.has(attr.name)) {
4595
+ if (anyAttributeWildcard) {
4596
+ const attrLocalName = attr.localName || attr.name.split(":")[1] || attr.name;
4597
+ const attrNamespace = attr.namespaceURI || null;
4598
+ if (attributeMatchesWildcard(attrLocalName, attrNamespace, anyAttributeWildcard, schema.targetNamespace)) {
4599
+ if (!shouldSkipWildcardValidation(anyAttributeWildcard.processContents)) {
4600
+ }
4601
+ continue;
4602
+ }
4603
+ }
3875
4604
  issues.push(
3876
4605
  createIssue2({
3877
4606
  code: ISSUE_CODES2.XML_UNEXPECTED_ATTRIBUTE,
@@ -4289,7 +5018,16 @@ ${writeNode(rootNode, 0)}`;
4289
5018
  return validateAll(children, startIndex, modelNode, context, pathParts, silent);
4290
5019
  case "any":
4291
5020
  if (startIndex < children.length) {
4292
- return { nextIndex: startIndex + 1, matched: true, matchedAny: true };
5021
+ const childNode = children[startIndex];
5022
+ const childLocalName = localName(childNode);
5023
+ const childNamespace = namespaceUri(childNode);
5024
+ if (elementMatchesWildcard(childLocalName, childNamespace, modelNode, context.schema.targetNamespace)) {
5025
+ if (isStrictWildcardValidation(modelNode.processContents)) {
5026
+ validateElementDecl(childNode, { name: childLocalName, typeName: null }, context, [...pathParts, childLocalName]);
5027
+ } else if (!shouldSkipWildcardValidation(modelNode.processContents)) {
5028
+ }
5029
+ return { nextIndex: startIndex + 1, matched: true, matchedAny: true };
5030
+ }
4293
5031
  }
4294
5032
  return { nextIndex: startIndex, matched: true, matchedAny: false };
4295
5033
  default:
@@ -4297,6 +5035,461 @@ ${writeNode(rootNode, 0)}`;
4297
5035
  }
4298
5036
  }
4299
5037
 
5038
+ // src/utils/xpathEvaluator.js
5039
+ function nodeMatchesQName(schema, node, qName) {
5040
+ if (!node || !qName) return false;
5041
+ const parsed = parseQName(qName);
5042
+ const expectedNs = resolveNamespaceUri(schema, parsed.prefix);
5043
+ const nodeLocal = node.localName || node.nodeName || null;
5044
+ const nodeNs = node.namespaceURI || null;
5045
+ if (parsed.prefix) {
5046
+ let nsToCompare = expectedNs || null;
5047
+ if (!nsToCompare) {
5048
+ if (typeof node.lookupNamespaceURI === "function") {
5049
+ try {
5050
+ nsToCompare = node.lookupNamespaceURI(parsed.prefix) || null;
5051
+ } catch (e) {
5052
+ nsToCompare = null;
5053
+ }
5054
+ }
5055
+ if (!nsToCompare && node.prefix) {
5056
+ return nodeLocal === parsed.localName && node.prefix === parsed.prefix;
5057
+ }
5058
+ }
5059
+ return nodeLocal === parsed.localName && (nodeNs || null) === (nsToCompare || null);
5060
+ }
5061
+ return nodeLocal === parsed.localName;
5062
+ }
5063
+ function collectDescendants(node, predicate) {
5064
+ const matches = [];
5065
+ function traverse(n) {
5066
+ if (!n || n.nodeType !== 1) return;
5067
+ if (predicate(n)) matches.push(n);
5068
+ for (const child of Array.from(n.childNodes || [])) {
5069
+ traverse(child);
5070
+ }
5071
+ }
5072
+ traverse(node);
5073
+ return matches;
5074
+ }
5075
+ function evaluateSelector(schema, startNodes, selectorXPath) {
5076
+ if (!selectorXPath || !Array.isArray(startNodes) || startNodes.length === 0) return [];
5077
+ let xpath = selectorXPath.trim();
5078
+ if (xpath.startsWith("./")) xpath = xpath.slice(2);
5079
+ if (xpath === "." || xpath === "") return startNodes;
5080
+ if (xpath.includes("//")) {
5081
+ return evaluateSelectorWithDescendant(schema, startNodes, xpath);
5082
+ }
5083
+ const segments = xpath.split("/");
5084
+ let nodes = startNodes;
5085
+ for (const raw of segments) {
5086
+ if (!raw || raw === ".") continue;
5087
+ const m = raw.match(/^([^\[]+)(?:\[(.+)\])?$/);
5088
+ if (!m) return [];
5089
+ const step = m[1];
5090
+ const predicate = m[2] || null;
5091
+ if (step === "*") {
5092
+ nodes = nodes.flatMap((n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1));
5093
+ } else if (step.startsWith("@")) {
5094
+ return [];
5095
+ } else {
5096
+ nodes = nodes.flatMap(
5097
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => {
5098
+ return nodeMatchesQName(schema, c, step);
5099
+ })
5100
+ );
5101
+ if (predicate && nodes.length) {
5102
+ const num = Number(predicate);
5103
+ if (Number.isInteger(num) && num > 0) {
5104
+ const idx = num - 1;
5105
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5106
+ } else {
5107
+ const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5108
+ if (attrMatch) {
5109
+ const attrName = attrMatch[1];
5110
+ const attrValue = attrMatch[2];
5111
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5112
+ } else {
5113
+ nodes = [];
5114
+ }
5115
+ }
5116
+ }
5117
+ }
5118
+ }
5119
+ return nodes;
5120
+ }
5121
+ function evaluateSelectorWithDescendant(schema, startNodes, xpath) {
5122
+ const fullParts = xpath.split(/\/\//);
5123
+ let nodes = startNodes;
5124
+ for (let partIdx = 0; partIdx < fullParts.length; partIdx++) {
5125
+ const part = fullParts[partIdx].trim();
5126
+ if (!part) continue;
5127
+ if (partIdx === 0) {
5128
+ if (part !== ".") {
5129
+ const segments = part.split("/");
5130
+ for (const seg of segments) {
5131
+ if (!seg || seg === ".") continue;
5132
+ const m = seg.match(/^([^\[]+)(?:\[(.+)\])?$/);
5133
+ if (!m) return [];
5134
+ const step = m[1];
5135
+ const predicate = m[2] || null;
5136
+ if (step === "*") {
5137
+ nodes = nodes.flatMap((n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1));
5138
+ } else if (step.startsWith("@")) {
5139
+ return [];
5140
+ } else {
5141
+ nodes = nodes.flatMap(
5142
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => nodeMatchesQName(schema, c, step))
5143
+ );
5144
+ if (predicate && nodes.length) {
5145
+ const num = Number(predicate);
5146
+ if (Number.isInteger(num) && num > 0) {
5147
+ const idx = num - 1;
5148
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5149
+ } else {
5150
+ const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5151
+ if (attrMatch) {
5152
+ const attrName = attrMatch[1];
5153
+ const attrValue = attrMatch[2];
5154
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5155
+ } else {
5156
+ nodes = [];
5157
+ }
5158
+ }
5159
+ }
5160
+ }
5161
+ }
5162
+ }
5163
+ } else {
5164
+ const segments = part.split("/");
5165
+ for (let segIdx = 0; segIdx < segments.length; segIdx++) {
5166
+ const segment = segments[segIdx];
5167
+ if (!segment || segment === ".") continue;
5168
+ const m = segment.match(/^([^\[]+)(?:\[(.+)\])?$/);
5169
+ if (!m) return [];
5170
+ const step = m[1];
5171
+ const predicate = m[2] || null;
5172
+ if (segIdx === 0) {
5173
+ const descendants = [];
5174
+ for (const node of nodes) {
5175
+ const matches = collectDescendants(node, (n) => {
5176
+ if (step === "*") return true;
5177
+ if (step.startsWith("@")) return false;
5178
+ return nodeMatchesQName(schema, n, step);
5179
+ });
5180
+ descendants.push(...matches);
5181
+ }
5182
+ nodes = descendants;
5183
+ if (predicate && nodes.length) {
5184
+ const predicateMatch = predicate.match(/^\[(.+)\]$/);
5185
+ if (predicateMatch) {
5186
+ const pred = predicateMatch[1];
5187
+ const num = Number(pred);
5188
+ if (Number.isInteger(num) && num > 0) {
5189
+ const idx = num - 1;
5190
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5191
+ } else {
5192
+ const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5193
+ if (attrMatch) {
5194
+ const attrName = attrMatch[1];
5195
+ const attrValue = attrMatch[2];
5196
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5197
+ } else {
5198
+ nodes = [];
5199
+ }
5200
+ }
5201
+ }
5202
+ }
5203
+ } else {
5204
+ nodes = nodes.flatMap(
5205
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => {
5206
+ if (step === "*") return true;
5207
+ if (step.startsWith("@")) return false;
5208
+ return nodeMatchesQName(schema, c, step);
5209
+ })
5210
+ );
5211
+ if (predicate && nodes.length) {
5212
+ const predicateMatch = predicate.match(/^\[(.+)\]$/);
5213
+ if (predicateMatch) {
5214
+ const pred = predicateMatch[1];
5215
+ const num = Number(pred);
5216
+ if (Number.isInteger(num) && num > 0) {
5217
+ const idx = num - 1;
5218
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5219
+ } else {
5220
+ const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5221
+ if (attrMatch) {
5222
+ const attrName = attrMatch[1];
5223
+ const attrValue = attrMatch[2];
5224
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5225
+ } else {
5226
+ nodes = [];
5227
+ }
5228
+ }
5229
+ }
5230
+ }
5231
+ }
5232
+ }
5233
+ }
5234
+ if (!nodes.length && partIdx < fullParts.length - 1) {
5235
+ return [];
5236
+ }
5237
+ }
5238
+ return nodes;
5239
+ }
5240
+ function evaluateField(schema, contextNode, fieldXPath) {
5241
+ if (!fieldXPath || !contextNode) return null;
5242
+ let xpath = fieldXPath.trim();
5243
+ if (xpath.startsWith("./")) xpath = xpath.slice(2);
5244
+ if (xpath === ".") return (contextNode.textContent || "").trim() || null;
5245
+ if (xpath.startsWith("@")) {
5246
+ const attr = xpath.slice(1);
5247
+ return contextNode.getAttribute(attr) ?? null;
5248
+ }
5249
+ if (xpath.includes("//")) {
5250
+ return evaluateFieldWithDescendant(schema, contextNode, xpath);
5251
+ }
5252
+ const segments = xpath.split("/");
5253
+ let nodes = [contextNode];
5254
+ for (let i = 0; i < segments.length; i += 1) {
5255
+ const raw = segments[i];
5256
+ if (!raw || raw === ".") continue;
5257
+ const m = raw.match(/^([^\[]+)(?:\[(.+)\])?$/);
5258
+ if (!m) return null;
5259
+ const step = m[1];
5260
+ const predicate = m[2] || null;
5261
+ if (step.startsWith("@")) {
5262
+ if (i !== segments.length - 1) return null;
5263
+ return nodes[0]?.getAttribute(step.slice(1)) ?? null;
5264
+ }
5265
+ nodes = nodes.flatMap(
5266
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1 && nodeMatchesQName(schema, c, step))
5267
+ );
5268
+ if (!nodes.length) return null;
5269
+ if (predicate) {
5270
+ const num = Number(predicate);
5271
+ if (Number.isInteger(num) && num > 0) {
5272
+ const idx = num - 1;
5273
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5274
+ } else {
5275
+ const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5276
+ if (attrMatch) {
5277
+ const attrName = attrMatch[1];
5278
+ const attrValue = attrMatch[2];
5279
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5280
+ } else {
5281
+ return null;
5282
+ }
5283
+ }
5284
+ }
5285
+ }
5286
+ const v = nodes[0];
5287
+ if (!v) return null;
5288
+ return (v.textContent || "").trim() || null;
5289
+ }
5290
+ function evaluateFieldWithDescendant(schema, contextNode, xpath) {
5291
+ const parts = xpath.split(/\/\//);
5292
+ let nodes = [contextNode];
5293
+ for (let i = 0; i < parts.length; i++) {
5294
+ const part = parts[i].trim();
5295
+ if (!part) continue;
5296
+ if (i === 0) {
5297
+ if (part !== "." && part !== "") {
5298
+ const val = evaluateField(schema, nodes[0], part);
5299
+ if (val !== null) return val;
5300
+ nodes = [];
5301
+ }
5302
+ } else {
5303
+ const m = part.match(/^([^\[]+)(?:\[(.+)\])?/);
5304
+ if (!m) return null;
5305
+ const step = m[1];
5306
+ const predicate = part.slice(m[0].length);
5307
+ if (step.startsWith("@")) {
5308
+ const attrName = step.slice(1);
5309
+ for (const node of nodes) {
5310
+ const descendants2 = collectDescendants(node, () => true);
5311
+ if (descendants2.length) {
5312
+ return descendants2[0]?.getAttribute(attrName) ?? null;
5313
+ }
5314
+ }
5315
+ return null;
5316
+ }
5317
+ const descendants = [];
5318
+ for (const node of nodes) {
5319
+ descendants.push(
5320
+ ...collectDescendants(node, (n) => {
5321
+ if (step === "*") return true;
5322
+ return nodeMatchesQName(schema, n, step);
5323
+ })
5324
+ );
5325
+ }
5326
+ nodes = descendants;
5327
+ if (!nodes.length) return null;
5328
+ if (predicate) {
5329
+ const predicateMatch = predicate.match(/^\[(.+)\]$/);
5330
+ if (predicateMatch) {
5331
+ const pred = predicateMatch[1];
5332
+ const num = Number(pred);
5333
+ if (Number.isInteger(num) && num > 0) {
5334
+ const idx = num - 1;
5335
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5336
+ } else {
5337
+ const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5338
+ if (attrMatch) {
5339
+ const attrName = attrMatch[1];
5340
+ const attrValue = attrMatch[2];
5341
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5342
+ }
5343
+ }
5344
+ }
5345
+ }
5346
+ if (nodes.length) {
5347
+ const v = nodes[0];
5348
+ return (v.textContent || "").trim() || null;
5349
+ }
5350
+ }
5351
+ }
5352
+ return null;
5353
+ }
5354
+
5355
+ // src/validation/identityConstraintValidator.js
5356
+ function localName2(node) {
5357
+ return node?.localName || node?.nodeName || null;
5358
+ }
5359
+ function namespaceUri2(node) {
5360
+ return node?.namespaceURI || null;
5361
+ }
5362
+ function collectOwnerXmlNodes(xmlRoot, ownerName, ownerNamespaceUri) {
5363
+ const matches = [];
5364
+ function traverse(node) {
5365
+ if (!node || node.nodeType !== 1) return;
5366
+ if (localName2(node) === ownerName && (ownerNamespaceUri == null || ownerNamespaceUri === namespaceUri2(node))) {
5367
+ matches.push(node);
5368
+ }
5369
+ for (const child of Array.from(node.children || [])) {
5370
+ traverse(child);
5371
+ }
5372
+ }
5373
+ traverse(xmlRoot);
5374
+ return matches;
5375
+ }
5376
+ function getConstraintOwnerNodes(schema, xmlRoot, constraint) {
5377
+ if (!constraint.ownerName) {
5378
+ return [xmlRoot];
5379
+ }
5380
+ return collectOwnerXmlNodes(
5381
+ xmlRoot,
5382
+ constraint.ownerName,
5383
+ constraint.ownerNamespaceUri
5384
+ );
5385
+ }
5386
+ function validateIdentityConstraints(schema, xmlRoot, getNodeLocation) {
5387
+ const issues = [];
5388
+ const keySets = /* @__PURE__ */ new Map();
5389
+ function buildKeySet(constraint) {
5390
+ if (keySets.has(constraint.name)) {
5391
+ return keySets.get(constraint.name);
5392
+ }
5393
+ const set = /* @__PURE__ */ new Set();
5394
+ const ownerNodes = getConstraintOwnerNodes(schema, xmlRoot, constraint);
5395
+ for (const ownerNode of ownerNodes) {
5396
+ const selected = evaluateSelector(schema, [ownerNode], constraint.selector?.xpath);
5397
+ for (const selectedNode of selected) {
5398
+ const tuple = constraint.fields.map((field) => evaluateField(schema, selectedNode, field.xpath));
5399
+ set.add(JSON.stringify(tuple));
5400
+ }
5401
+ }
5402
+ keySets.set(constraint.name, set);
5403
+ return set;
5404
+ }
5405
+ for (const constraint of schema.identityConstraints || []) {
5406
+ const ownerNodes = getConstraintOwnerNodes(schema, xmlRoot, constraint);
5407
+ if (!ownerNodes.length) {
5408
+ continue;
5409
+ }
5410
+ const valueIndex = /* @__PURE__ */ new Map();
5411
+ const referenceKeyConstraint = schema.identityConstraints.find(
5412
+ (item) => item.kind === "key" && item.name === parseQName(constraint.refer || "").localName
5413
+ );
5414
+ const referenceKeySet = constraint.kind === "keyref" && referenceKeyConstraint ? buildKeySet(referenceKeyConstraint) : null;
5415
+ for (const ownerNode of ownerNodes) {
5416
+ const selected = evaluateSelector(schema, [ownerNode], constraint.selector?.xpath);
5417
+ for (const selectedNode of selected) {
5418
+ const tuple = constraint.fields.map((field) => evaluateField(schema, selectedNode, field.xpath));
5419
+ const tupleKey = JSON.stringify(tuple);
5420
+ const rawLocation = getNodeLocation ? getNodeLocation(selectedNode) : null;
5421
+ const location = rawLocation || { line: constraint.line || 1, column: constraint.column || 1 };
5422
+ if (tuple.some((value) => value == null || value === "")) {
5423
+ if (constraint.kind === "key") {
5424
+ issues.push(
5425
+ createIssue({
5426
+ code: ISSUE_CODES.XML_KEY_NULL_VIOLATION,
5427
+ severity: "error",
5428
+ message: `xs:key '${constraint.name}' requires non-empty values for all fields.`,
5429
+ line: location.line,
5430
+ column: location.column,
5431
+ path: constraint.path,
5432
+ source: "xml",
5433
+ nodeKind: "element",
5434
+ name: constraint.name,
5435
+ details: {
5436
+ selector: constraint.selector?.xpath,
5437
+ fields: constraint.fields.map((field) => field.xpath)
5438
+ }
5439
+ })
5440
+ );
5441
+ }
5442
+ }
5443
+ if (constraint.kind === "key" || constraint.kind === "unique") {
5444
+ if (valueIndex.has(tupleKey)) {
5445
+ issues.push(
5446
+ createIssue({
5447
+ code: constraint.kind === "key" ? ISSUE_CODES.XML_KEY_VIOLATION : ISSUE_CODES.XML_UNIQUE_VIOLATION,
5448
+ severity: "error",
5449
+ message: `Duplicate ${constraint.kind} value for '${constraint.name}'.`,
5450
+ line: location.line,
5451
+ column: location.column,
5452
+ path: constraint.path,
5453
+ source: "xml",
5454
+ nodeKind: "element",
5455
+ name: constraint.name,
5456
+ details: {
5457
+ selector: constraint.selector?.xpath,
5458
+ fields: constraint.fields.map((field) => field.xpath)
5459
+ }
5460
+ })
5461
+ );
5462
+ }
5463
+ valueIndex.set(tupleKey, true);
5464
+ }
5465
+ if (constraint.kind === "keyref" && referenceKeySet) {
5466
+ if (!referenceKeySet.has(tupleKey)) {
5467
+ issues.push(
5468
+ createIssue({
5469
+ code: ISSUE_CODES.XML_KEYREF_VIOLATION,
5470
+ severity: "error",
5471
+ message: `xs:keyref '${constraint.name}' references a missing key value.`,
5472
+ line: location.line,
5473
+ column: location.column,
5474
+ path: constraint.path,
5475
+ source: "xml",
5476
+ nodeKind: "element",
5477
+ name: constraint.name,
5478
+ details: {
5479
+ refer: constraint.refer,
5480
+ selector: constraint.selector?.xpath,
5481
+ fields: constraint.fields.map((field) => field.xpath)
5482
+ }
5483
+ })
5484
+ );
5485
+ }
5486
+ }
5487
+ }
5488
+ }
5489
+ }
5490
+ return issues;
5491
+ }
5492
+
4300
5493
  // src/validation/builtinTypeValidators.js
4301
5494
  function isIntegerString(value) {
4302
5495
  return /^[-+]?\d+$/.test(value);
@@ -4794,12 +5987,12 @@ ${writeNode(rootNode, 0)}`;
4794
5987
  const end = tagText.indexOf(quoteChar, start);
4795
5988
  return end >= start ? start : -1;
4796
5989
  }
4797
- function findTextContentOffset(text, tagEndOffset, localName3) {
5990
+ function findTextContentOffset(text, tagEndOffset, localName4) {
4798
5991
  let i = tagEndOffset + 1;
4799
5992
  while (i < text.length && /\s/.test(text[i])) {
4800
5993
  i += 1;
4801
5994
  }
4802
- if (text.startsWith(`</${localName3}`, i) || text[i] === "<") {
5995
+ if (text.startsWith(`</${localName4}`, i) || text[i] === "<") {
4803
5996
  return -1;
4804
5997
  }
4805
5998
  return i < text.length ? i : -1;
@@ -4826,10 +6019,20 @@ ${writeNode(rootNode, 0)}`;
4826
6019
  }
4827
6020
  };
4828
6021
  }
4829
- const orderedNodes = [
4830
- documentElement,
4831
- ...Array.from(documentElement.querySelectorAll("*"))
4832
- ];
6022
+ let orderedNodes = null;
6023
+ if (typeof documentElement.querySelectorAll === "function") {
6024
+ orderedNodes = [documentElement, ...Array.from(documentElement.querySelectorAll("*"))];
6025
+ } else {
6026
+ let collect = function(node) {
6027
+ if (!node || node.nodeType !== 1) return;
6028
+ orderedNodes.push(node);
6029
+ for (const child of Array.from(node.children || [])) {
6030
+ collect(child);
6031
+ }
6032
+ };
6033
+ orderedNodes = [];
6034
+ collect(documentElement);
6035
+ }
4833
6036
  let searchFrom = 0;
4834
6037
  for (const node of orderedNodes) {
4835
6038
  const expectedLocalName = getNodeLocalName(node);
@@ -4906,10 +6109,10 @@ ${writeNode(rootNode, 0)}`;
4906
6109
  (child) => child.nodeType === 1
4907
6110
  );
4908
6111
  }
4909
- function localName2(node) {
6112
+ function localName3(node) {
4910
6113
  return node?.localName || node?.nodeName || null;
4911
6114
  }
4912
- function namespaceUri2(node) {
6115
+ function namespaceUri3(node) {
4913
6116
  return node?.namespaceURI || null;
4914
6117
  }
4915
6118
  function determineRootElement(schema, xmlRootName, xmlRootNs, options) {
@@ -4954,8 +6157,8 @@ ${writeNode(rootNode, 0)}`;
4954
6157
  }
4955
6158
  const locator = createXmlSourceLocator(xmlText, xmlParse.document);
4956
6159
  const xmlRoot = xmlParse.document.documentElement;
4957
- const xmlRootName = localName2(xmlRoot);
4958
- const xmlRootNs = namespaceUri2(xmlRoot);
6160
+ const xmlRootName = localName3(xmlRoot);
6161
+ const xmlRootNs = namespaceUri3(xmlRoot);
4959
6162
  const issues = [...parseIssues];
4960
6163
  if (!xmlRoot) {
4961
6164
  return {
@@ -5075,7 +6278,7 @@ ${writeNode(rootNode, 0)}`;
5075
6278
  const children2 = elementChildren3(xmlRoot);
5076
6279
  if (children2.length > 0) {
5077
6280
  for (const childNode of children2) {
5078
- const childName = localName2(childNode);
6281
+ const childName = localName3(childNode);
5079
6282
  issues.push(
5080
6283
  createIssue({
5081
6284
  code: ISSUE_CODES.XML_UNEXPECTED_ELEMENT,
@@ -5087,7 +6290,7 @@ ${writeNode(rootNode, 0)}`;
5087
6290
  nodeKind: "element",
5088
6291
  name: childName,
5089
6292
  details: {
5090
- namespaceUri: namespaceUri2(childNode)
6293
+ namespaceUri: namespaceUri3(childNode)
5091
6294
  }
5092
6295
  })
5093
6296
  );
@@ -5164,7 +6367,7 @@ ${writeNode(rootNode, 0)}`;
5164
6367
  if (result.nextIndex < children.length) {
5165
6368
  for (let i = result.nextIndex; i < children.length; i += 1) {
5166
6369
  const childNode = children[i];
5167
- const childName = localName2(childNode);
6370
+ const childName = localName3(childNode);
5168
6371
  issues.push(
5169
6372
  createIssue({
5170
6373
  code: ISSUE_CODES.XML_UNEXPECTED_ELEMENT,
@@ -5176,7 +6379,7 @@ ${writeNode(rootNode, 0)}`;
5176
6379
  nodeKind: "element",
5177
6380
  name: childName,
5178
6381
  details: {
5179
- namespaceUri: namespaceUri2(childNode)
6382
+ namespaceUri: namespaceUri3(childNode)
5180
6383
  }
5181
6384
  })
5182
6385
  );
@@ -5207,6 +6410,12 @@ ${writeNode(rootNode, 0)}`;
5207
6410
  );
5208
6411
  }
5209
6412
  }
6413
+ const identityConstraintIssues = validateIdentityConstraints(
6414
+ schema,
6415
+ xmlRoot,
6416
+ locator.getNodeLocation
6417
+ );
6418
+ issues.push(...identityConstraintIssues);
5210
6419
  return {
5211
6420
  data: {
5212
6421
  xmlValid: !issues.some((issue) => issue.severity === "error")