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
  */
@@ -45,6 +45,10 @@ var ISSUE_CODES = {
45
45
  UNKNOWN_GROUP: "UNKNOWN_GROUP",
46
46
  UNKNOWN_ATTRIBUTE_GROUP: "UNKNOWN_ATTRIBUTE_GROUP",
47
47
  MISSING_BASE_TYPE: "MISSING_BASE_TYPE",
48
+ INVALID_CONSTRAINT_SELECTOR: "INVALID_CONSTRAINT_SELECTOR",
49
+ INVALID_CONSTRAINT_FIELD: "INVALID_CONSTRAINT_FIELD",
50
+ UNKNOWN_KEY_REFERENCE: "UNKNOWN_KEY_REFERENCE",
51
+ DUPLICATE_CONSTRAINT_NAME: "DUPLICATE_CONSTRAINT_NAME",
48
52
  UNSUPPORTED_FEATURE: "UNSUPPORTED_FEATURE",
49
53
  INVALID_OCCURS_RANGE: "INVALID_OCCURS_RANGE",
50
54
  INVALID_DEFAULT_FIXED_COMBINATION: "INVALID_DEFAULT_FIXED_COMBINATION",
@@ -61,6 +65,12 @@ var ISSUE_CODES = {
61
65
  XML_VALUE_INVALID: "XML_VALUE_INVALID",
62
66
  XML_ENUMERATION_MISMATCH: "XML_ENUMERATION_MISMATCH",
63
67
  XML_VALUE_REQUIRED: "XML_VALUE_REQUIRED",
68
+ XML_KEY_VIOLATION: "XML_KEY_VIOLATION",
69
+ XML_KEY_NULL_VIOLATION: "XML_KEY_NULL_VIOLATION",
70
+ XML_KEYREF_VIOLATION: "XML_KEYREF_VIOLATION",
71
+ XML_UNIQUE_VIOLATION: "XML_UNIQUE_VIOLATION",
72
+ XML_ANY_STRICT_VALIDATION_FAILED: "XML_ANY_STRICT_VALIDATION_FAILED",
73
+ XML_ANYATTRIBUTE_STRICT_VALIDATION_FAILED: "XML_ANYATTRIBUTE_STRICT_VALIDATION_FAILED",
64
74
  XML_PATTERN_MISMATCH: "XML_PATTERN_MISMATCH",
65
75
  XML_LENGTH_MISMATCH: "XML_LENGTH_MISMATCH",
66
76
  XML_MIN_LENGTH_VIOLATION: "XML_MIN_LENGTH_VIOLATION",
@@ -87,6 +97,9 @@ var ISSUE_CODES = {
87
97
  XSD_RESTRICTION_NOT_SUBSET: "XSD_RESTRICTION_NOT_SUBSET",
88
98
  XSD_RESTRICTION_OCCURS_WIDENED: "XSD_RESTRICTION_OCCURS_WIDENED",
89
99
  XSD_RESTRICTION_ATTRIBUTE_WIDENED: "XSD_RESTRICTION_ATTRIBUTE_WIDENED",
100
+ XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE: "XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE",
101
+ XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE: "XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE",
102
+ XSD_RESTRICTION_WILDCARD_INCOMPATIBLE: "XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
90
103
  XSD_INCLUDE_NOT_PROVIDED: "XSD_INCLUDE_NOT_PROVIDED",
91
104
  XSD_IMPORT_NOT_PROVIDED: "XSD_IMPORT_NOT_PROVIDED",
92
105
  XSD_INCLUDE_NAMESPACE_MISMATCH: "XSD_INCLUDE_NAMESPACE_MISMATCH",
@@ -162,6 +175,7 @@ function createEmptySchemaModel() {
162
175
  },
163
176
  importedSchemas: [],
164
177
  roots: [],
178
+ identityConstraints: [],
165
179
  references: {
166
180
  types: [],
167
181
  refs: [],
@@ -193,7 +207,7 @@ function normalizeUse(value) {
193
207
  function createElementDecl({
194
208
  name = null,
195
209
  qName = null,
196
- namespaceUri: namespaceUri3 = null,
210
+ namespaceUri: namespaceUri4 = null,
197
211
  typeName = null,
198
212
  refName = null,
199
213
  inlineType = null,
@@ -202,6 +216,7 @@ function createElementDecl({
202
216
  defaultValue = null,
203
217
  fixedValue = null,
204
218
  nillable = false,
219
+ identityConstraints = [],
205
220
  line = null,
206
221
  column = null,
207
222
  path = null
@@ -210,7 +225,7 @@ function createElementDecl({
210
225
  kind: "element",
211
226
  name,
212
227
  qName,
213
- namespaceUri: namespaceUri3,
228
+ namespaceUri: namespaceUri4,
214
229
  typeName,
215
230
  refName,
216
231
  inlineType,
@@ -219,6 +234,7 @@ function createElementDecl({
219
234
  defaultValue,
220
235
  fixedValue,
221
236
  nillable,
237
+ identityConstraints,
222
238
  line,
223
239
  column,
224
240
  path
@@ -227,7 +243,7 @@ function createElementDecl({
227
243
  function createAttributeDecl({
228
244
  name = null,
229
245
  qName = null,
230
- namespaceUri: namespaceUri3 = null,
246
+ namespaceUri: namespaceUri4 = null,
231
247
  typeName = null,
232
248
  refName = null,
233
249
  inlineType = null,
@@ -242,7 +258,7 @@ function createAttributeDecl({
242
258
  kind: "attribute",
243
259
  name,
244
260
  qName,
245
- namespaceUri: namespaceUri3,
261
+ namespaceUri: namespaceUri4,
246
262
  typeName,
247
263
  refName,
248
264
  inlineType,
@@ -257,13 +273,14 @@ function createAttributeDecl({
257
273
  function createComplexTypeDecl({
258
274
  name = null,
259
275
  qName = null,
260
- namespaceUri: namespaceUri3 = null,
276
+ namespaceUri: namespaceUri4 = null,
261
277
  content = null,
262
278
  attributes = [],
263
279
  derivation = { kind: null, baseTypeName: null },
264
280
  contentModel = "complex",
265
281
  mixed = false,
266
282
  abstract = false,
283
+ identityConstraints = [],
267
284
  line = null,
268
285
  column = null,
269
286
  path = null
@@ -272,13 +289,14 @@ function createComplexTypeDecl({
272
289
  kind: "complexType",
273
290
  name,
274
291
  qName,
275
- namespaceUri: namespaceUri3,
292
+ namespaceUri: namespaceUri4,
276
293
  content,
277
294
  attributes,
278
295
  derivation,
279
296
  contentModel,
280
297
  mixed,
281
298
  abstract,
299
+ identityConstraints,
282
300
  line,
283
301
  column,
284
302
  path
@@ -287,7 +305,7 @@ function createComplexTypeDecl({
287
305
  function createSimpleTypeDecl({
288
306
  name = null,
289
307
  qName = null,
290
- namespaceUri: namespaceUri3 = null,
308
+ namespaceUri: namespaceUri4 = null,
291
309
  baseTypeName = null,
292
310
  facets = {},
293
311
  enumerations = [],
@@ -299,7 +317,7 @@ function createSimpleTypeDecl({
299
317
  kind: "simpleType",
300
318
  name,
301
319
  qName,
302
- namespaceUri: namespaceUri3,
320
+ namespaceUri: namespaceUri4,
303
321
  baseTypeName,
304
322
  facets,
305
323
  enumerations,
@@ -311,7 +329,7 @@ function createSimpleTypeDecl({
311
329
  function createGroupDecl({
312
330
  name,
313
331
  qName = null,
314
- namespaceUri: namespaceUri3 = null,
332
+ namespaceUri: namespaceUri4 = null,
315
333
  content = null,
316
334
  line = null,
317
335
  column = null,
@@ -321,7 +339,7 @@ function createGroupDecl({
321
339
  kind: "group",
322
340
  name,
323
341
  qName,
324
- namespaceUri: namespaceUri3,
342
+ namespaceUri: namespaceUri4,
325
343
  content,
326
344
  line,
327
345
  column,
@@ -331,7 +349,7 @@ function createGroupDecl({
331
349
  function createAttributeGroupDecl({
332
350
  name,
333
351
  qName = null,
334
- namespaceUri: namespaceUri3 = null,
352
+ namespaceUri: namespaceUri4 = null,
335
353
  attributes = [],
336
354
  line = null,
337
355
  column = null,
@@ -341,7 +359,7 @@ function createAttributeGroupDecl({
341
359
  kind: "attributeGroup",
342
360
  name,
343
361
  qName,
344
- namespaceUri: namespaceUri3,
362
+ namespaceUri: namespaceUri4,
345
363
  attributes,
346
364
  line,
347
365
  column,
@@ -362,6 +380,37 @@ function createAttributeGroupRef({
362
380
  path
363
381
  };
364
382
  }
383
+ function createIdentityConstraint({
384
+ kind = null,
385
+ name = null,
386
+ qName = null,
387
+ namespaceUri: namespaceUri4 = null,
388
+ selector = null,
389
+ fields = [],
390
+ refer = null,
391
+ ownerName = null,
392
+ ownerNamespaceUri = null,
393
+ ownerPath = null,
394
+ line = null,
395
+ column = null,
396
+ path = null
397
+ } = {}) {
398
+ return {
399
+ kind,
400
+ name,
401
+ qName,
402
+ namespaceUri: namespaceUri4,
403
+ selector,
404
+ fields,
405
+ refer,
406
+ ownerName,
407
+ ownerNamespaceUri,
408
+ ownerPath,
409
+ line,
410
+ column,
411
+ path
412
+ };
413
+ }
365
414
  function createSequenceNode({
366
415
  children = [],
367
416
  minOccurs = 1,
@@ -436,9 +485,11 @@ function createGroupRefNode({
436
485
  }
437
486
  function createAnyNode({
438
487
  namespace = null,
439
- processContents = null,
488
+ processContents = "strict",
440
489
  minOccurs = 1,
441
490
  maxOccurs = 1,
491
+ notNamespace = [],
492
+ notQName = [],
442
493
  line = null,
443
494
  column = null,
444
495
  path = null
@@ -446,9 +497,31 @@ function createAnyNode({
446
497
  return {
447
498
  kind: "any",
448
499
  namespace,
449
- processContents,
500
+ processContents: processContents || "strict",
450
501
  minOccurs,
451
502
  maxOccurs,
503
+ notNamespace,
504
+ notQName,
505
+ line,
506
+ column,
507
+ path
508
+ };
509
+ }
510
+ function createAnyAttributeNode({
511
+ namespace = null,
512
+ processContents = "strict",
513
+ notNamespace = [],
514
+ notQName = [],
515
+ line = null,
516
+ column = null,
517
+ path = null
518
+ } = {}) {
519
+ return {
520
+ kind: "anyAttribute",
521
+ namespace,
522
+ processContents: processContents || "strict",
523
+ notNamespace,
524
+ notQName,
452
525
  line,
453
526
  column,
454
527
  path
@@ -533,8 +606,8 @@ function resolveQName(schema, qName) {
533
606
  namespaceUri: resolveNamespaceUri(schema, parsed.prefix)
534
607
  };
535
608
  }
536
- function makeLookupKey(namespaceUri3, localName3) {
537
- return `${namespaceUri3 || ""}::${localName3 || ""}`;
609
+ function makeLookupKey(namespaceUri4, localName4) {
610
+ return `${namespaceUri4 || ""}::${localName4 || ""}`;
538
611
  }
539
612
  function isBuiltinType(typeName, schema = null) {
540
613
  const q = parseQName(typeName);
@@ -550,41 +623,41 @@ function isBuiltinType(typeName, schema = null) {
550
623
  function getLocalName(name) {
551
624
  return parseQName(name).localName;
552
625
  }
553
- function lookupBucketByNamespace(bucket, namespaceUri3, localName3) {
554
- if (!bucket || !localName3) return null;
555
- return bucket[makeLookupKey(namespaceUri3, localName3)] || null;
626
+ function lookupBucketByNamespace(bucket, namespaceUri4, localName4) {
627
+ if (!bucket || !localName4) return null;
628
+ return bucket[makeLookupKey(namespaceUri4, localName4)] || null;
556
629
  }
557
- function lookupInSchemaBucket(bucketName, schema, namespaceUri3, localName3) {
558
- return lookupBucketByNamespace(schema?.globals?.[bucketName], namespaceUri3, localName3);
630
+ function lookupInSchemaBucket(bucketName, schema, namespaceUri4, localName4) {
631
+ return lookupBucketByNamespace(schema?.globals?.[bucketName], namespaceUri4, localName4);
559
632
  }
560
- function lookupInImportedSchemas(bucketName, schema, namespaceUri3, localName3, visited = /* @__PURE__ */ new Set()) {
561
- if (!schema || !namespaceUri3) return null;
633
+ function lookupInImportedSchemas(bucketName, schema, namespaceUri4, localName4, visited = /* @__PURE__ */ new Set()) {
634
+ if (!schema || !namespaceUri4) return null;
562
635
  if (visited.has(schema)) return null;
563
636
  visited.add(schema);
564
637
  for (const importedSchema of schema.importedSchemas || []) {
565
638
  if (!importedSchema) continue;
566
- if ((importedSchema.targetNamespace || null) === namespaceUri3) {
639
+ if ((importedSchema.targetNamespace || null) === namespaceUri4) {
567
640
  const direct = lookupInSchemaBucket(
568
641
  bucketName,
569
642
  importedSchema,
570
- namespaceUri3,
571
- localName3
643
+ namespaceUri4,
644
+ localName4
572
645
  );
573
646
  if (direct) return direct;
574
647
  }
575
648
  const nested = lookupInImportedSchemas(
576
649
  bucketName,
577
650
  importedSchema,
578
- namespaceUri3,
579
- localName3,
651
+ namespaceUri4,
652
+ localName4,
580
653
  visited
581
654
  );
582
655
  if (nested) return nested;
583
656
  }
584
657
  return null;
585
658
  }
586
- function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName3, visited = /* @__PURE__ */ new Set()) {
587
- if (!schema || !localName3) return null;
659
+ function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName4, visited = /* @__PURE__ */ new Set()) {
660
+ if (!schema || !localName4) return null;
588
661
  if (visited.has(schema)) return null;
589
662
  visited.add(schema);
590
663
  const targetNs = schema.targetNamespace || null;
@@ -596,14 +669,14 @@ function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName3, vi
596
669
  bucketName,
597
670
  importedSchema,
598
671
  importedNs,
599
- localName3
672
+ localName4
600
673
  );
601
674
  if (direct) return direct;
602
675
  }
603
676
  const nested = lookupInImportedSchemasForUnprefixed(
604
677
  bucketName,
605
678
  importedSchema,
606
- localName3,
679
+ localName4,
607
680
  visited
608
681
  );
609
682
  if (nested) return nested;
@@ -614,24 +687,24 @@ function lookupByQName(bucketName, schema, name) {
614
687
  if (!schema || !name) return null;
615
688
  const parsed = parseQName(name);
616
689
  const resolved = resolveQName(schema, name);
617
- const localName3 = resolved.localName;
618
- if (!localName3) return null;
690
+ const localName4 = resolved.localName;
691
+ if (!localName4) return null;
619
692
  if (parsed.prefix) {
620
693
  const direct = lookupInSchemaBucket(
621
694
  bucketName,
622
695
  schema,
623
696
  resolved.namespaceUri,
624
- localName3
697
+ localName4
625
698
  );
626
699
  if (direct) return direct;
627
700
  return lookupInImportedSchemas(
628
701
  bucketName,
629
702
  schema,
630
703
  resolved.namespaceUri,
631
- localName3
704
+ localName4
632
705
  );
633
706
  }
634
- const noNamespace = lookupInSchemaBucket(bucketName, schema, null, localName3);
707
+ const noNamespace = lookupInSchemaBucket(bucketName, schema, null, localName4);
635
708
  if (noNamespace) return noNamespace;
636
709
  const sameSchemaNs = schema.targetNamespace || null;
637
710
  if (sameSchemaNs !== null) {
@@ -639,13 +712,13 @@ function lookupByQName(bucketName, schema, name) {
639
712
  bucketName,
640
713
  schema,
641
714
  sameSchemaNs,
642
- localName3
715
+ localName4
643
716
  );
644
717
  if (hostNamespaceDecl) return hostNamespaceDecl;
645
718
  const importedSameNamespaceDecl = lookupInImportedSchemasForUnprefixed(
646
719
  bucketName,
647
720
  schema,
648
- localName3
721
+ localName4
649
722
  );
650
723
  if (importedSameNamespaceDecl) return importedSameNamespaceDecl;
651
724
  }
@@ -773,11 +846,6 @@ function getEffectiveContent(schema, complexTypeDecl) {
773
846
 
774
847
  // src/parser/buildSchemaModel.js
775
848
  var UNSUPPORTED_NODE_FEATURES = /* @__PURE__ */ new Set([
776
- "key",
777
- "keyref",
778
- "unique",
779
- "any",
780
- "anyAttribute",
781
849
  "redefine",
782
850
  "notation"
783
851
  ]);
@@ -840,6 +908,9 @@ function mergeGlobalsIntoSchema(targetSchema, sourceSchema, issues, createDuplic
840
908
  ...sourceSchema.externalRefs.imports || []
841
909
  );
842
910
  targetSchema.importedSchemas.push(...sourceSchema.importedSchemas || []);
911
+ targetSchema.identityConstraints.push(
912
+ ...sourceSchema.identityConstraints || []
913
+ );
843
914
  for (const feature of sourceSchema.usedFeatures || []) {
844
915
  targetSchema.usedFeatures.add(feature);
845
916
  }
@@ -892,17 +963,17 @@ function escapeRegExp(value) {
892
963
  }
893
964
  function locateNodeInSource(xsdText, lineStarts, node) {
894
965
  if (!xsdText || !node) return { line: null, column: null };
895
- const localName3 = node.localName;
966
+ const localName4 = node.localName;
896
967
  const name = node.getAttribute("name");
897
968
  const ref = node.getAttribute("ref");
898
969
  const base = node.getAttribute("base");
899
970
  const type = node.getAttribute("type");
900
971
  const candidates = [
901
- name ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\bname=(["'])${escapeRegExp(name)}\\1` : null,
902
- ref ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\bref=(["'])${escapeRegExp(ref)}\\1` : null,
903
- base ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\bbase=(["'])${escapeRegExp(base)}\\1` : null,
904
- type ? `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b[^>]*\\btype=(["'])${escapeRegExp(type)}\\1` : null,
905
- `<(?:[\\w.-]+:)?${escapeRegExp(localName3)}\\b`
972
+ name ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bname=(["'])${escapeRegExp(name)}\\1` : null,
973
+ ref ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bref=(["'])${escapeRegExp(ref)}\\1` : null,
974
+ base ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\bbase=(["'])${escapeRegExp(base)}\\1` : null,
975
+ type ? `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b[^>]*\\btype=(["'])${escapeRegExp(type)}\\1` : null,
976
+ `<(?:[\\w.-]+:)?${escapeRegExp(localName4)}\\b`
906
977
  ].filter(Boolean);
907
978
  for (const pattern of candidates) {
908
979
  const regex = new RegExp(pattern, "m");
@@ -925,9 +996,9 @@ function buildPath(parentPath, node) {
925
996
  return `${parentPath}/${kind}${qualifier}`;
926
997
  }
927
998
  function registerGlobal(schema, issues, bucketName, duplicateCode, decl) {
928
- const localName3 = stripNamespacePrefix(decl.name);
929
- if (!localName3) return;
930
- const key = makeLookupKey(decl.namespaceUri, localName3);
999
+ const localName4 = stripNamespacePrefix(decl.name);
1000
+ if (!localName4) return;
1001
+ const key = makeLookupKey(decl.namespaceUri, localName4);
931
1002
  if (schema.globals[bucketName][key]) {
932
1003
  issues.push(
933
1004
  createIssue({
@@ -954,15 +1025,15 @@ function collectUnsupportedFeature(schema, feature) {
954
1025
  schema.unsupportedFeatures.push(feature);
955
1026
  }
956
1027
  function collectNodeDiagnostics(schema, issues, node, path, loc) {
957
- const localName3 = node.localName;
958
- schema.usedFeatures.add(localName3);
959
- if (UNSUPPORTED_NODE_FEATURES.has(localName3)) {
1028
+ const localName4 = node.localName;
1029
+ schema.usedFeatures.add(localName4);
1030
+ if (UNSUPPORTED_NODE_FEATURES.has(localName4)) {
960
1031
  collectUnsupportedFeature(schema, {
961
- feature: `xs:${localName3}`,
1032
+ feature: `xs:${localName4}`,
962
1033
  line: loc.line,
963
1034
  column: loc.column,
964
1035
  path,
965
- nodeKind: localName3,
1036
+ nodeKind: localName4,
966
1037
  name: node.getAttribute("name") || null
967
1038
  });
968
1039
  }
@@ -972,7 +1043,7 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
972
1043
  line: loc.line,
973
1044
  column: loc.column,
974
1045
  path,
975
- nodeKind: localName3,
1046
+ nodeKind: localName4,
976
1047
  name: node.getAttribute("name") || null
977
1048
  });
978
1049
  }
@@ -982,47 +1053,47 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
982
1053
  line: loc.line,
983
1054
  column: loc.column,
984
1055
  path,
985
- nodeKind: localName3,
1056
+ nodeKind: localName4,
986
1057
  name: node.getAttribute("name") || node.getAttribute("ref") || null
987
1058
  });
988
1059
  }
989
- if ((localName3 === "element" || localName3 === "attribute") && node.hasAttribute("ref")) {
1060
+ if ((localName4 === "element" || localName4 === "attribute") && node.hasAttribute("ref")) {
990
1061
  collectReference(schema, "refs", {
991
1062
  refName: node.getAttribute("ref"),
992
1063
  line: loc.line,
993
1064
  column: loc.column,
994
1065
  path,
995
- nodeKind: localName3,
1066
+ nodeKind: localName4,
996
1067
  name: node.getAttribute("name") || null
997
1068
  });
998
1069
  }
999
- if ((localName3 === "extension" || localName3 === "restriction") && node.hasAttribute("base")) {
1070
+ if ((localName4 === "extension" || localName4 === "restriction") && node.hasAttribute("base")) {
1000
1071
  collectReference(schema, "baseTypes", {
1001
1072
  baseTypeName: node.getAttribute("base"),
1002
1073
  line: loc.line,
1003
1074
  column: loc.column,
1004
1075
  path,
1005
- nodeKind: localName3,
1076
+ nodeKind: localName4,
1006
1077
  name: node.getAttribute("name") || null
1007
1078
  });
1008
1079
  }
1009
- if (localName3 === "group" && node.hasAttribute("ref")) {
1080
+ if (localName4 === "group" && node.hasAttribute("ref")) {
1010
1081
  collectReference(schema, "groupRefs", {
1011
1082
  refName: node.getAttribute("ref"),
1012
1083
  line: loc.line,
1013
1084
  column: loc.column,
1014
1085
  path,
1015
- nodeKind: localName3,
1086
+ nodeKind: localName4,
1016
1087
  name: node.getAttribute("name") || null
1017
1088
  });
1018
1089
  }
1019
- if (localName3 === "attributeGroup" && node.hasAttribute("ref")) {
1090
+ if (localName4 === "attributeGroup" && node.hasAttribute("ref")) {
1020
1091
  collectReference(schema, "attributeGroupRefs", {
1021
1092
  refName: node.getAttribute("ref"),
1022
1093
  line: loc.line,
1023
1094
  column: loc.column,
1024
1095
  path,
1025
- nodeKind: localName3,
1096
+ nodeKind: localName4,
1026
1097
  name: node.getAttribute("name") || null
1027
1098
  });
1028
1099
  }
@@ -1038,13 +1109,13 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
1038
1109
  column: loc.column,
1039
1110
  path,
1040
1111
  source: "xsd",
1041
- nodeKind: localName3,
1112
+ nodeKind: localName4,
1042
1113
  name: node.getAttribute("name") || null,
1043
1114
  details: { minOccurs, maxOccurs }
1044
1115
  })
1045
1116
  );
1046
1117
  }
1047
- if ((localName3 === "element" || localName3 === "attribute") && node.hasAttribute("default") && node.hasAttribute("fixed")) {
1118
+ if ((localName4 === "element" || localName4 === "attribute") && node.hasAttribute("default") && node.hasAttribute("fixed")) {
1048
1119
  issues.push(
1049
1120
  createIssue({
1050
1121
  code: ISSUE_CODES.INVALID_DEFAULT_FIXED_COMBINATION,
@@ -1054,7 +1125,7 @@ function collectNodeDiagnostics(schema, issues, node, path, loc) {
1054
1125
  column: loc.column,
1055
1126
  path,
1056
1127
  source: "xsd",
1057
- nodeKind: localName3,
1128
+ nodeKind: localName4,
1058
1129
  name: node.getAttribute("name") || node.getAttribute("ref") || null,
1059
1130
  details: {
1060
1131
  defaultValue: node.getAttribute("default"),
@@ -1135,11 +1206,11 @@ function parseSimpleType(node, xsdText, lineStarts, parentPath, schema, issues)
1135
1206
  enumerations = parsed.enumerations;
1136
1207
  }
1137
1208
  const qName = node.getAttribute("name");
1138
- const namespaceUri3 = schema.targetNamespace || null;
1209
+ const namespaceUri4 = schema.targetNamespace || null;
1139
1210
  return createSimpleTypeDecl({
1140
1211
  name: qName ? parseQName(qName).localName : null,
1141
1212
  qName,
1142
- namespaceUri: namespaceUri3,
1213
+ namespaceUri: namespaceUri4,
1143
1214
  baseTypeName,
1144
1215
  facets,
1145
1216
  enumerations,
@@ -1164,11 +1235,11 @@ function parseAttribute(node, xsdText, lineStarts, parentPath, schema, issues) {
1164
1235
  issues
1165
1236
  ) : null;
1166
1237
  const qName = node.getAttribute("name");
1167
- const namespaceUri3 = getDeclarationNamespaceUri(schema, node, "attribute");
1238
+ const namespaceUri4 = getDeclarationNamespaceUri(schema, node, "attribute");
1168
1239
  return createAttributeDecl({
1169
1240
  name: qName ? parseQName(qName).localName : null,
1170
1241
  qName,
1171
- namespaceUri: namespaceUri3,
1242
+ namespaceUri: namespaceUri4,
1172
1243
  typeName: node.getAttribute("type"),
1173
1244
  refName: node.getAttribute("ref"),
1174
1245
  inlineType,
@@ -1209,6 +1280,10 @@ function parseAttributesContainer(nodes, xsdText, lineStarts, parentPath, schema
1209
1280
  issues
1210
1281
  )
1211
1282
  );
1283
+ } else if (child.localName === "anyAttribute") {
1284
+ attributes.push(
1285
+ parseAnyAttribute(child, xsdText, lineStarts, parentPath, schema, issues)
1286
+ );
1212
1287
  }
1213
1288
  }
1214
1289
  return attributes;
@@ -1245,11 +1320,26 @@ function parseElement(node, xsdText, lineStarts, parentPath, schema, issues) {
1245
1320
  );
1246
1321
  }
1247
1322
  const qName = node.getAttribute("name");
1248
- const namespaceUri3 = getDeclarationNamespaceUri(schema, node, "element");
1323
+ const namespaceUri4 = getDeclarationNamespaceUri(schema, node, "element");
1324
+ const identityConstraints = children.filter(
1325
+ (child) => ["key", "keyref", "unique"].includes(child.localName)
1326
+ ).map(
1327
+ (child) => parseIdentityConstraint(
1328
+ child,
1329
+ xsdText,
1330
+ lineStarts,
1331
+ path,
1332
+ schema,
1333
+ issues,
1334
+ qName ? parseQName(qName).localName : null,
1335
+ namespaceUri4,
1336
+ path
1337
+ )
1338
+ );
1249
1339
  return createElementDecl({
1250
1340
  name: qName ? parseQName(qName).localName : null,
1251
1341
  qName,
1252
- namespaceUri: namespaceUri3,
1342
+ namespaceUri: namespaceUri4,
1253
1343
  typeName: node.getAttribute("type"),
1254
1344
  refName: node.getAttribute("ref"),
1255
1345
  inlineType,
@@ -1258,6 +1348,7 @@ function parseElement(node, xsdText, lineStarts, parentPath, schema, issues) {
1258
1348
  defaultValue: node.getAttribute("default"),
1259
1349
  fixedValue: node.getAttribute("fixed"),
1260
1350
  nillable: node.getAttribute("nillable") === "true",
1351
+ identityConstraints,
1261
1352
  line: loc.line,
1262
1353
  column: loc.column,
1263
1354
  path
@@ -1276,20 +1367,101 @@ function parseGroupRef(node, xsdText, lineStarts, parentPath, schema, issues) {
1276
1367
  path
1277
1368
  });
1278
1369
  }
1370
+ function parseWildcardNamespace(namespaceStr) {
1371
+ if (!namespaceStr) return null;
1372
+ const trimmed = namespaceStr.trim();
1373
+ if (!trimmed) return null;
1374
+ if (trimmed.includes(" ")) {
1375
+ return trimmed.split(/\s+/).filter((ns) => ns);
1376
+ }
1377
+ return trimmed;
1378
+ }
1379
+ function parseNotNamespace(notNamespaceStr) {
1380
+ if (!notNamespaceStr) return [];
1381
+ const trimmed = notNamespaceStr.trim();
1382
+ if (!trimmed) return [];
1383
+ if (trimmed.includes(" ")) {
1384
+ return trimmed.split(/\s+/).filter((ns) => ns);
1385
+ }
1386
+ return [trimmed];
1387
+ }
1388
+ function parseNotQName(notQNameStr) {
1389
+ if (!notQNameStr) return [];
1390
+ const trimmed = notQNameStr.trim();
1391
+ if (!trimmed) return [];
1392
+ if (trimmed.includes(" ")) {
1393
+ return trimmed.split(/\s+/).filter((qn) => qn);
1394
+ }
1395
+ return [trimmed];
1396
+ }
1279
1397
  function parseAny(node, xsdText, lineStarts, parentPath, schema, issues) {
1280
1398
  const path = buildPath(parentPath, node);
1281
1399
  const loc = locateNodeInSource(xsdText, lineStarts, node);
1282
1400
  collectNodeDiagnostics(schema, issues, node, path, loc);
1283
1401
  return createAnyNode({
1284
- namespace: node.getAttribute("namespace"),
1402
+ namespace: parseWildcardNamespace(node.getAttribute("namespace")),
1285
1403
  processContents: node.getAttribute("processContents"),
1286
1404
  minOccurs: normalizeOccurs(node.getAttribute("minOccurs"), 1),
1287
1405
  maxOccurs: normalizeOccurs(node.getAttribute("maxOccurs"), 1),
1406
+ notNamespace: parseNotNamespace(node.getAttribute("notNamespace")),
1407
+ notQName: parseNotQName(node.getAttribute("notQName")),
1288
1408
  line: loc.line,
1289
1409
  column: loc.column,
1290
1410
  path
1291
1411
  });
1292
1412
  }
1413
+ function parseAnyAttribute(node, xsdText, lineStarts, parentPath, schema, issues) {
1414
+ const path = buildPath(parentPath, node);
1415
+ const loc = locateNodeInSource(xsdText, lineStarts, node);
1416
+ collectNodeDiagnostics(schema, issues, node, path, loc);
1417
+ return createAnyAttributeNode({
1418
+ namespace: parseWildcardNamespace(node.getAttribute("namespace")),
1419
+ processContents: node.getAttribute("processContents"),
1420
+ notNamespace: parseNotNamespace(node.getAttribute("notNamespace")),
1421
+ notQName: parseNotQName(node.getAttribute("notQName")),
1422
+ line: loc.line,
1423
+ column: loc.column,
1424
+ path
1425
+ });
1426
+ }
1427
+ function parseIdentityConstraint(node, xsdText, lineStarts, parentPath, schema, issues, ownerName, ownerNamespaceUri, ownerPath) {
1428
+ const path = buildPath(parentPath, node);
1429
+ const loc = locateNodeInSource(xsdText, lineStarts, node);
1430
+ collectNodeDiagnostics(schema, issues, node, path, loc);
1431
+ const selectorNode = elementChildren(node).find(
1432
+ (child) => child.localName === "selector"
1433
+ );
1434
+ const selector = selectorNode ? {
1435
+ xpath: selectorNode.getAttribute("xpath"),
1436
+ path: buildPath(path, selectorNode)
1437
+ } : null;
1438
+ const fields = elementChildren(node).filter((child) => child.localName === "field").map((child) => ({
1439
+ xpath: child.getAttribute("xpath"),
1440
+ line: locateNodeInSource(xsdText, lineStarts, child).line,
1441
+ column: locateNodeInSource(xsdText, lineStarts, child).column,
1442
+ path: buildPath(path, child)
1443
+ })).filter((field) => field.xpath != null);
1444
+ const qName = node.getAttribute("name");
1445
+ const name = qName ? parseQName(qName).localName : null;
1446
+ const namespaceUri4 = ownerNamespaceUri || schema.targetNamespace || null;
1447
+ const constraint = createIdentityConstraint({
1448
+ kind: node.localName,
1449
+ name,
1450
+ qName,
1451
+ namespaceUri: namespaceUri4,
1452
+ selector,
1453
+ fields,
1454
+ refer: node.getAttribute("refer"),
1455
+ ownerName,
1456
+ ownerNamespaceUri,
1457
+ ownerPath,
1458
+ line: loc.line,
1459
+ column: loc.column,
1460
+ path
1461
+ });
1462
+ schema.identityConstraints.push(constraint);
1463
+ return constraint;
1464
+ }
1293
1465
  function parseContentNode(node, xsdText, lineStarts, parentPath, schema, issues) {
1294
1466
  const path = buildPath(parentPath, node);
1295
1467
  const loc = locateNodeInSource(xsdText, lineStarts, node);
@@ -1436,6 +1608,22 @@ function parseComplexType(node, xsdText, lineStarts, parentPath, schema, issues)
1436
1608
  let derivation = { kind: null, baseTypeName: null };
1437
1609
  let contentModel = "complex";
1438
1610
  const children = elementChildren(node);
1611
+ const namespaceUri4 = schema.targetNamespace || null;
1612
+ const identityConstraints = children.filter(
1613
+ (child) => ["key", "keyref", "unique"].includes(child.localName)
1614
+ ).map(
1615
+ (child) => parseIdentityConstraint(
1616
+ child,
1617
+ xsdText,
1618
+ lineStarts,
1619
+ path,
1620
+ schema,
1621
+ issues,
1622
+ null,
1623
+ namespaceUri4,
1624
+ path
1625
+ )
1626
+ );
1439
1627
  const directContentNode = children.find(
1440
1628
  (child) => ["sequence", "choice", "all", "group", "element", "any"].includes(
1441
1629
  child.localName
@@ -1495,17 +1683,17 @@ function parseComplexType(node, xsdText, lineStarts, parentPath, schema, issues)
1495
1683
  );
1496
1684
  }
1497
1685
  const qName = node.getAttribute("name");
1498
- const namespaceUri3 = schema.targetNamespace || null;
1499
1686
  return createComplexTypeDecl({
1500
1687
  name: qName ? parseQName(qName).localName : null,
1501
1688
  qName,
1502
- namespaceUri: namespaceUri3,
1689
+ namespaceUri: namespaceUri4,
1503
1690
  content,
1504
1691
  attributes,
1505
1692
  derivation,
1506
1693
  contentModel,
1507
1694
  mixed: node.getAttribute("mixed") === "true",
1508
1695
  abstract: node.getAttribute("abstract") === "true",
1696
+ identityConstraints,
1509
1697
  line: loc.line,
1510
1698
  column: loc.column,
1511
1699
  path
@@ -1519,11 +1707,11 @@ function parseGroup(node, xsdText, lineStarts, parentPath, schema, issues) {
1519
1707
  (child) => ["sequence", "choice", "all"].includes(child.localName)
1520
1708
  );
1521
1709
  const qName = node.getAttribute("name");
1522
- const namespaceUri3 = schema.targetNamespace || null;
1710
+ const namespaceUri4 = schema.targetNamespace || null;
1523
1711
  return createGroupDecl({
1524
1712
  name: qName ? parseQName(qName).localName : null,
1525
1713
  qName,
1526
- namespaceUri: namespaceUri3,
1714
+ namespaceUri: namespaceUri4,
1527
1715
  content: contentNode ? parseContentNode(contentNode, xsdText, lineStarts, path, schema, issues) : null,
1528
1716
  line: loc.line,
1529
1717
  column: loc.column,
@@ -1545,11 +1733,11 @@ function parseAttributeGroup(node, xsdText, lineStarts, parentPath, schema, issu
1545
1733
  issues
1546
1734
  );
1547
1735
  const qName = node.getAttribute("name");
1548
- const namespaceUri3 = schema.targetNamespace || null;
1736
+ const namespaceUri4 = schema.targetNamespace || null;
1549
1737
  return createAttributeGroupDecl({
1550
1738
  name: qName ? parseQName(qName).localName : null,
1551
1739
  qName,
1552
- namespaceUri: namespaceUri3,
1740
+ namespaceUri: namespaceUri4,
1553
1741
  attributes,
1554
1742
  line: loc.line,
1555
1743
  column: loc.column,
@@ -1653,24 +1841,24 @@ function resolveExternalDocument(ref, externalDocuments) {
1653
1841
  }
1654
1842
  }
1655
1843
  if (ref?.kind === "import" && ref.namespace) {
1656
- const namespaceMatches = entries.filter((entry) => {
1844
+ const namespaceMatches2 = entries.filter((entry) => {
1657
1845
  const declaredTargetNamespace = getDeclaredTargetNamespaceFromText(
1658
1846
  entry.text
1659
1847
  );
1660
1848
  return (declaredTargetNamespace || null) === (ref.namespace || null);
1661
1849
  });
1662
- if (namespaceMatches.length === 1) {
1850
+ if (namespaceMatches2.length === 1) {
1663
1851
  return {
1664
1852
  kind: "namespace",
1665
- entry: namespaceMatches[0],
1666
- matches: namespaceMatches
1853
+ entry: namespaceMatches2[0],
1854
+ matches: namespaceMatches2
1667
1855
  };
1668
1856
  }
1669
- if (namespaceMatches.length > 1) {
1857
+ if (namespaceMatches2.length > 1) {
1670
1858
  return {
1671
1859
  kind: "ambiguous-namespace",
1672
1860
  entry: null,
1673
- matches: namespaceMatches
1861
+ matches: namespaceMatches2
1674
1862
  };
1675
1863
  }
1676
1864
  }
@@ -2287,6 +2475,115 @@ function checkRestrictedAttributes(schema, derivedType, baseType, issues) {
2287
2475
  }
2288
2476
  }
2289
2477
  }
2478
+ function checkWildcardRestriction(schema, derivedType, baseType, issues) {
2479
+ const derivedContent = getEffectiveContent(schema, derivedType);
2480
+ const baseContent = getEffectiveContent(schema, baseType);
2481
+ const derivedWildcards = [];
2482
+ const baseWildcards = [];
2483
+ function collectWildcards(node, arr) {
2484
+ if (!node) return;
2485
+ if (node.kind === "any") {
2486
+ arr.push(node);
2487
+ return;
2488
+ }
2489
+ if (node.children) {
2490
+ for (const child of asArray(node.children)) {
2491
+ collectWildcards(child, arr);
2492
+ }
2493
+ }
2494
+ }
2495
+ collectWildcards(derivedContent, derivedWildcards);
2496
+ collectWildcards(baseContent, baseWildcards);
2497
+ if (derivedWildcards.length > 0 && baseWildcards.length === 0) {
2498
+ issues.push(
2499
+ buildRestrictionIssue(
2500
+ "XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
2501
+ `Restricted type introduces wildcard elements that base type does not have.`,
2502
+ derivedType
2503
+ )
2504
+ );
2505
+ }
2506
+ const derivedAttrs = asArray(getEffectiveAttributes(schema, derivedType));
2507
+ const baseAttrs = asArray(getEffectiveAttributes(schema, baseType));
2508
+ const derivedHasAnyAttribute = derivedAttrs.some((a) => a?.kind === "anyAttribute");
2509
+ const baseHasAnyAttribute = baseAttrs.some((a) => a?.kind === "anyAttribute");
2510
+ if (derivedHasAnyAttribute && !baseHasAnyAttribute) {
2511
+ issues.push(
2512
+ buildRestrictionIssue(
2513
+ "XSD_RESTRICTION_WILDCARD_INCOMPATIBLE",
2514
+ `Restricted type introduces anyAttribute that base type does not have.`,
2515
+ derivedType
2516
+ )
2517
+ );
2518
+ }
2519
+ }
2520
+ function checkOccurrenceCompatibility(derived, base, name) {
2521
+ const dMin = typeof derived.minOccurs === "number" ? derived.minOccurs : 1;
2522
+ const bMin = typeof base.minOccurs === "number" ? base.minOccurs : 1;
2523
+ const dMax = maxToNumber(derived.maxOccurs ?? 1);
2524
+ const bMax = maxToNumber(base.maxOccurs ?? 1);
2525
+ return dMin >= bMin && dMax <= bMax;
2526
+ }
2527
+ function checkComplexContentRestriction(schema, derivedType, baseType, issues) {
2528
+ const derivedContent = getEffectiveContent(schema, derivedType);
2529
+ const baseContent = getEffectiveContent(schema, baseType);
2530
+ if (!derivedContent || !baseContent) return;
2531
+ const derivedFlat = flattenContent(derivedContent, []);
2532
+ const baseFlat = flattenContent(baseContent, []);
2533
+ const baseMap = new Map(baseFlat.map((item) => [item.name, item]));
2534
+ for (const item of derivedFlat) {
2535
+ const baseItem = baseMap.get(item.name);
2536
+ if (!baseItem) {
2537
+ issues.push(
2538
+ buildRestrictionIssue(
2539
+ "XSD_RESTRICTION_NOT_SUBSET",
2540
+ `Restricted type contains element '${item.name}' not in base type.`,
2541
+ item
2542
+ )
2543
+ );
2544
+ continue;
2545
+ }
2546
+ if (!checkOccurrenceCompatibility(item, baseItem, item.name)) {
2547
+ issues.push(
2548
+ buildRestrictionIssue(
2549
+ "XSD_RESTRICTION_OCCURRENCE_INCOMPATIBLE",
2550
+ `Restricted type has incompatible occurrence constraints for '${item.name}'.`,
2551
+ item
2552
+ )
2553
+ );
2554
+ }
2555
+ }
2556
+ }
2557
+ function checkSimpleContentRestriction(schema, derivedType, baseType, issues) {
2558
+ if (baseType.contentModel !== "simple") {
2559
+ issues.push(
2560
+ buildRestrictionIssue(
2561
+ "XSD_RESTRICTION_NOT_SUBSET",
2562
+ `SimpleContent restriction requires base type to have simple content.`,
2563
+ derivedType
2564
+ )
2565
+ );
2566
+ }
2567
+ const derivedAttrs = asArray(getEffectiveAttributes(schema, derivedType));
2568
+ const baseAttrs = asArray(getEffectiveAttributes(schema, baseType));
2569
+ const baseAttrMap = new Map(
2570
+ baseAttrs.filter((attr) => attr?.kind === "attribute").map((attr) => [localDeclName(attr), attr])
2571
+ );
2572
+ for (const attr of derivedAttrs) {
2573
+ if (attr?.kind !== "attribute") continue;
2574
+ const name = localDeclName(attr);
2575
+ const baseAttr = baseAttrMap.get(name);
2576
+ if (!baseAttr && !baseAttrs.some((a) => a?.kind === "anyAttribute")) {
2577
+ issues.push(
2578
+ buildRestrictionIssue(
2579
+ "XSD_RESTRICTION_ATTRIBUTE_INCOMPATIBLE",
2580
+ `SimpleContent restricted type adds attribute '${name}' not in base type.`,
2581
+ attr
2582
+ )
2583
+ );
2584
+ }
2585
+ }
2586
+ }
2290
2587
  function runRestrictionDiagnostics(schema) {
2291
2588
  const issues = [];
2292
2589
  for (const complexType of Object.values(schema.globals.complexTypes || {})) {
@@ -2296,6 +2593,12 @@ function runRestrictionDiagnostics(schema) {
2296
2593
  if (!baseType) continue;
2297
2594
  checkRestrictedContentSubset(schema, complexType, baseType, issues);
2298
2595
  checkRestrictedAttributes(schema, complexType, baseType, issues);
2596
+ checkWildcardRestriction(schema, complexType, baseType, issues);
2597
+ if (complexType.contentModel === "complex" && baseType.contentModel === "complex") {
2598
+ checkComplexContentRestriction(schema, complexType, baseType, issues);
2599
+ } else if (complexType.contentModel === "simple" && baseType.contentModel === "simple") {
2600
+ checkSimpleContentRestriction(schema, complexType, baseType, issues);
2601
+ }
2299
2602
  }
2300
2603
  return issues;
2301
2604
  }
@@ -2332,6 +2635,188 @@ function runDefaultFixedDiagnostics(schema) {
2332
2635
  return issues;
2333
2636
  }
2334
2637
 
2638
+ // src/diagnostics/schemaIdentityConstraintDiagnostics.js
2639
+ function isValidConstraintXPath(xpath) {
2640
+ if (!xpath || typeof xpath !== "string") return false;
2641
+ const trimmed = xpath.trim();
2642
+ if (!trimmed) return false;
2643
+ let normalized = trimmed;
2644
+ if (trimmed.startsWith("./")) {
2645
+ if (trimmed.startsWith(".//")) normalized = trimmed.slice(1);
2646
+ else normalized = trimmed.slice(2);
2647
+ }
2648
+ if (normalized.startsWith("/") && !normalized.startsWith("//")) return false;
2649
+ if (normalized.includes("///")) return false;
2650
+ let segments = normalized.split(
2651
+ /\/+/
2652
+ );
2653
+ if (normalized.startsWith("//")) segments = segments.slice(1);
2654
+ if (normalized.endsWith("//")) segments = segments.slice(0, -1);
2655
+ if (segments.some((segment) => segment.length === 0)) return false;
2656
+ for (const segment of segments) {
2657
+ if (segment === ".") continue;
2658
+ if (segment === "*") continue;
2659
+ if (segment.startsWith("@")) {
2660
+ const attrName = segment.slice(1);
2661
+ if (!/^[A-Za-z_][\w.-]*$/.test(attrName)) return false;
2662
+ continue;
2663
+ }
2664
+ const parsed = parseQName(segment);
2665
+ if (!parsed.localName) return false;
2666
+ }
2667
+ return true;
2668
+ }
2669
+ function getConstraintKey(constraint) {
2670
+ return `${constraint.ownerPath || ""}::${constraint.name || ""}`;
2671
+ }
2672
+ function findReferencedKey(schema, refer) {
2673
+ if (!refer) return null;
2674
+ const referName = parseQName(refer).localName;
2675
+ return schema.identityConstraints.find(
2676
+ (constraint) => constraint.kind === "key" && constraint.name === referName
2677
+ );
2678
+ }
2679
+ function runIdentityConstraintDiagnostics(schema) {
2680
+ const issues = [];
2681
+ const seenNames = /* @__PURE__ */ new Set();
2682
+ for (const constraint of schema.identityConstraints || []) {
2683
+ const key = getConstraintKey(constraint);
2684
+ if (seenNames.has(key)) {
2685
+ issues.push(
2686
+ createIssue({
2687
+ code: ISSUE_CODES.DUPLICATE_CONSTRAINT_NAME,
2688
+ severity: "error",
2689
+ message: `Duplicate identity constraint name '${constraint.name}' in the same scope.`,
2690
+ line: constraint.line,
2691
+ column: constraint.column,
2692
+ path: constraint.path,
2693
+ source: "xsd",
2694
+ nodeKind: constraint.kind,
2695
+ name: constraint.name,
2696
+ details: {
2697
+ ownerPath: constraint.ownerPath,
2698
+ ownerName: constraint.ownerName
2699
+ }
2700
+ })
2701
+ );
2702
+ } else {
2703
+ seenNames.add(key);
2704
+ }
2705
+ if (!constraint.selector || !constraint.selector.xpath) {
2706
+ issues.push(
2707
+ createIssue({
2708
+ code: ISSUE_CODES.INVALID_CONSTRAINT_SELECTOR,
2709
+ severity: "error",
2710
+ message: `Identity constraint '${constraint.name || constraint.kind}' is missing a selector xpath.`,
2711
+ line: constraint.line,
2712
+ column: constraint.column,
2713
+ path: constraint.path,
2714
+ source: "xsd",
2715
+ nodeKind: constraint.kind,
2716
+ name: constraint.name,
2717
+ details: {
2718
+ ownerPath: constraint.ownerPath,
2719
+ ownerName: constraint.ownerName
2720
+ }
2721
+ })
2722
+ );
2723
+ } else if (!isValidConstraintXPath(constraint.selector.xpath)) {
2724
+ issues.push(
2725
+ createIssue({
2726
+ code: ISSUE_CODES.INVALID_CONSTRAINT_SELECTOR,
2727
+ severity: "error",
2728
+ message: `Invalid selector xpath '${constraint.selector.xpath}'.`,
2729
+ line: constraint.line,
2730
+ column: constraint.column,
2731
+ path: constraint.selector.path,
2732
+ source: "xsd",
2733
+ nodeKind: constraint.kind,
2734
+ name: constraint.name,
2735
+ details: {
2736
+ selector: constraint.selector.xpath,
2737
+ ownerPath: constraint.ownerPath
2738
+ }
2739
+ })
2740
+ );
2741
+ }
2742
+ if (!constraint.fields?.length) {
2743
+ issues.push(
2744
+ createIssue({
2745
+ code: ISSUE_CODES.INVALID_CONSTRAINT_FIELD,
2746
+ severity: "error",
2747
+ message: `Identity constraint '${constraint.name || constraint.kind}' must declare at least one field.`,
2748
+ line: constraint.line,
2749
+ column: constraint.column,
2750
+ path: constraint.path,
2751
+ source: "xsd",
2752
+ nodeKind: constraint.kind,
2753
+ name: constraint.name,
2754
+ details: { ownerPath: constraint.ownerPath }
2755
+ })
2756
+ );
2757
+ } else {
2758
+ for (const field of constraint.fields) {
2759
+ if (!field.xpath || !isValidConstraintXPath(field.xpath)) {
2760
+ issues.push(
2761
+ createIssue({
2762
+ code: ISSUE_CODES.INVALID_CONSTRAINT_FIELD,
2763
+ severity: "error",
2764
+ message: `Invalid field xpath '${field.xpath}'.`,
2765
+ line: field.line,
2766
+ column: field.column,
2767
+ path: field.path,
2768
+ source: "xsd",
2769
+ nodeKind: constraint.kind,
2770
+ name: constraint.name,
2771
+ details: {
2772
+ field: field.xpath,
2773
+ ownerPath: constraint.ownerPath
2774
+ }
2775
+ })
2776
+ );
2777
+ }
2778
+ }
2779
+ }
2780
+ if (constraint.kind === "keyref") {
2781
+ if (!constraint.refer) {
2782
+ issues.push(
2783
+ createIssue({
2784
+ code: ISSUE_CODES.UNKNOWN_KEY_REFERENCE,
2785
+ severity: "error",
2786
+ message: `xs:keyref '${constraint.name || "unnamed"}' is missing a refer attribute.`,
2787
+ line: constraint.line,
2788
+ column: constraint.column,
2789
+ path: constraint.path,
2790
+ source: "xsd",
2791
+ nodeKind: constraint.kind,
2792
+ name: constraint.name,
2793
+ details: { ownerPath: constraint.ownerPath }
2794
+ })
2795
+ );
2796
+ } else if (!findReferencedKey(schema, constraint.refer)) {
2797
+ issues.push(
2798
+ createIssue({
2799
+ code: ISSUE_CODES.UNKNOWN_KEY_REFERENCE,
2800
+ severity: "error",
2801
+ message: `xs:keyref refers to unknown key '${constraint.refer}'.`,
2802
+ line: constraint.line,
2803
+ column: constraint.column,
2804
+ path: constraint.path,
2805
+ source: "xsd",
2806
+ nodeKind: constraint.kind,
2807
+ name: constraint.name,
2808
+ details: {
2809
+ refer: constraint.refer,
2810
+ ownerPath: constraint.ownerPath
2811
+ }
2812
+ })
2813
+ );
2814
+ }
2815
+ }
2816
+ }
2817
+ return issues;
2818
+ }
2819
+
2335
2820
  // src/diagnostics/schemaImportDiagnostics.js
2336
2821
  function normalizeSchemaPath2(value) {
2337
2822
  if (!value || typeof value !== "string") return null;
@@ -2440,6 +2925,130 @@ function runImportDiagnostics(schema, options = {}) {
2440
2925
  return issues;
2441
2926
  }
2442
2927
 
2928
+ // src/diagnostics/schemaWildcardDiagnostics.js
2929
+ function validateWildcardNamespace(namespace, path) {
2930
+ if (!namespace) return null;
2931
+ const trimmed = namespace.trim();
2932
+ if (!trimmed) return null;
2933
+ const parts = trimmed.split(/\s+/);
2934
+ for (const part of parts) {
2935
+ if (part === "##any" || part === "##other" || part === "##targetNamespace") {
2936
+ continue;
2937
+ }
2938
+ if (!part.includes(":") && part !== "") {
2939
+ return createIssue({
2940
+ code: "INVALID_WILDCARD_NAMESPACE",
2941
+ severity: "warning",
2942
+ message: `Invalid namespace in wildcard constraint: '${part}'. Expected ##any, ##other, ##targetNamespace, or a valid namespace URI.`,
2943
+ path
2944
+ });
2945
+ }
2946
+ }
2947
+ return null;
2948
+ }
2949
+ function validateProcessContents(processContents, path) {
2950
+ if (!processContents) return null;
2951
+ const trimmed = processContents.trim();
2952
+ if (trimmed === "strict" || trimmed === "lax" || trimmed === "skip") {
2953
+ return null;
2954
+ }
2955
+ return createIssue({
2956
+ code: "INVALID_PROCESS_CONTENTS",
2957
+ severity: "error",
2958
+ message: `Invalid processContents value: '${processContents}'. Must be 'strict', 'lax', or 'skip'.`,
2959
+ path
2960
+ });
2961
+ }
2962
+ function validateSingleWildcard(wildcardNode, nodeName) {
2963
+ const issues = [];
2964
+ const nsIssue = validateWildcardNamespace(wildcardNode.namespace, wildcardNode.path);
2965
+ if (nsIssue) {
2966
+ issues.push(nsIssue);
2967
+ }
2968
+ const pcIssue = validateProcessContents(wildcardNode.processContents, wildcardNode.path);
2969
+ if (pcIssue) {
2970
+ issues.push(pcIssue);
2971
+ }
2972
+ if (wildcardNode.notNamespace && wildcardNode.notNamespace.length > 0) {
2973
+ if (wildcardNode.namespace !== "##other" && wildcardNode.namespace !== "##targetNamespace") {
2974
+ issues.push(
2975
+ createIssue({
2976
+ code: "INVALID_NOT_NAMESPACE_USAGE",
2977
+ severity: "warning",
2978
+ message: `notNamespace is only meaningful with ##other or ##targetNamespace namespace constraint.`,
2979
+ path: wildcardNode.path
2980
+ })
2981
+ );
2982
+ }
2983
+ }
2984
+ if (wildcardNode.notQName && wildcardNode.notQName.length > 0) {
2985
+ for (const qname of wildcardNode.notQName) {
2986
+ if (!qname || qname.trim() === "") {
2987
+ issues.push(
2988
+ createIssue({
2989
+ code: "INVALID_NOT_QNAME",
2990
+ severity: "warning",
2991
+ message: `Empty QName in notQName constraint.`,
2992
+ path: wildcardNode.path
2993
+ })
2994
+ );
2995
+ break;
2996
+ }
2997
+ }
2998
+ }
2999
+ return issues;
3000
+ }
3001
+ function findWildcardsInContent(node, wildcards) {
3002
+ if (!node) return;
3003
+ if (node.kind === "any" || node.kind === "anyAttribute") {
3004
+ wildcards.push(node);
3005
+ return;
3006
+ }
3007
+ if (node.children && Array.isArray(node.children)) {
3008
+ for (const child of node.children) {
3009
+ findWildcardsInContent(child, wildcards);
3010
+ }
3011
+ }
3012
+ }
3013
+ function findWildcardsInAttributes(attributes, wildcards) {
3014
+ if (!attributes || !Array.isArray(attributes)) return;
3015
+ for (const attr of attributes) {
3016
+ if (attr.kind === "anyAttribute") {
3017
+ wildcards.push(attr);
3018
+ }
3019
+ }
3020
+ }
3021
+ function runWildcardDiagnostics(schema) {
3022
+ const issues = [];
3023
+ const wildcards = [];
3024
+ for (const elem of Object.values(schema.globals.elements || {})) {
3025
+ if (elem.inlineType?.content) {
3026
+ findWildcardsInContent(elem.inlineType.content, wildcards);
3027
+ }
3028
+ if (elem.inlineType?.attributes) {
3029
+ findWildcardsInAttributes(elem.inlineType.attributes, wildcards);
3030
+ }
3031
+ }
3032
+ for (const complexType of Object.values(schema.globals.complexTypes || {})) {
3033
+ if (complexType.content) {
3034
+ findWildcardsInContent(complexType.content, wildcards);
3035
+ }
3036
+ if (complexType.attributes) {
3037
+ findWildcardsInAttributes(complexType.attributes, wildcards);
3038
+ }
3039
+ }
3040
+ for (const group of Object.values(schema.globals.groups || {})) {
3041
+ if (group.content) {
3042
+ findWildcardsInContent(group.content, wildcards);
3043
+ }
3044
+ }
3045
+ for (const wildcard of wildcards) {
3046
+ const wildcardIssues = validateSingleWildcard(wildcard, wildcard.kind);
3047
+ issues.push(...wildcardIssues);
3048
+ }
3049
+ return issues;
3050
+ }
3051
+
2443
3052
  // src/diagnostics/schemaDiagnostics.js
2444
3053
  function buildStats(schema) {
2445
3054
  return {
@@ -2467,11 +3076,14 @@ function getSupportedFeatures(schema) {
2467
3076
  "element",
2468
3077
  "extension",
2469
3078
  "group",
3079
+ "key",
3080
+ "keyref",
2470
3081
  "restriction",
2471
3082
  "schema",
2472
3083
  "sequence",
2473
3084
  "simpleContent",
2474
- "simpleType"
3085
+ "simpleType",
3086
+ "unique"
2475
3087
  ].includes(name)
2476
3088
  ).map((name) => `xs:${name}`)
2477
3089
  );
@@ -2608,7 +3220,11 @@ function runSchemaDiagnostics(schema, options = {}) {
2608
3220
  checkMissingBaseTypes(schema, issues);
2609
3221
  checkUnknownGroups(schema, issues);
2610
3222
  checkUnknownAttributeGroups(schema, issues);
3223
+ const identityIssues = runIdentityConstraintDiagnostics(schema);
3224
+ issues.push(...identityIssues);
2611
3225
  emitUnsupportedFeatureWarnings(schema, issues, options);
3226
+ const wildcardIssues = runWildcardDiagnostics(schema);
3227
+ issues.push(...wildcardIssues);
2612
3228
  const facetIssues = runFacetDiagnostics(schema, options);
2613
3229
  issues.push(...facetIssues);
2614
3230
  const restrictionIssues = runRestrictionDiagnostics(schema);
@@ -2629,7 +3245,7 @@ function runSchemaDiagnostics(schema, options = {}) {
2629
3245
  }
2630
3246
 
2631
3247
  // src/version.js
2632
- var ENGINE_VERSION = "v0.1.1";
3248
+ var ENGINE_VERSION = "v0.2.1";
2633
3249
 
2634
3250
  // src/utils/result.js
2635
3251
  function summarizeIssues(issues = []) {
@@ -2695,7 +3311,7 @@ function createTreeNode({
2695
3311
  refName = null,
2696
3312
  baseTypeName = null,
2697
3313
  derivation = null,
2698
- namespaceUri: namespaceUri3 = null,
3314
+ namespaceUri: namespaceUri4 = null,
2699
3315
  minOccurs = 1,
2700
3316
  maxOccurs = 1,
2701
3317
  use = null,
@@ -2712,7 +3328,7 @@ function createTreeNode({
2712
3328
  refName,
2713
3329
  baseTypeName,
2714
3330
  derivation,
2715
- namespaceUri: namespaceUri3,
3331
+ namespaceUri: namespaceUri4,
2716
3332
  minOccurs,
2717
3333
  maxOccurs,
2718
3334
  use,
@@ -2724,9 +3340,9 @@ function createTreeNode({
2724
3340
  }
2725
3341
 
2726
3342
  // src/tree/extractTree.js
2727
- function buildQualifiedLabel(name, namespaceUri3) {
3343
+ function buildQualifiedLabel(name, namespaceUri4) {
2728
3344
  if (!name) return name;
2729
- return namespaceUri3 ? `{${namespaceUri3}} ${name}` : name;
3345
+ return namespaceUri4 ? `{${namespaceUri4}} ${name}` : name;
2730
3346
  }
2731
3347
  function asArray2(value) {
2732
3348
  return Array.isArray(value) ? value : [];
@@ -3367,8 +3983,8 @@ function mergeAttributes(target, source) {
3367
3983
  Object.assign(target, source);
3368
3984
  }
3369
3985
  function qualifiedElementName(schema, elementDecl, state, isRoot = false) {
3370
- const localName3 = elementDecl.name || elementDecl.refName || "element";
3371
- const bare = localName3.includes(":") ? localName3.split(":")[1] : localName3;
3986
+ const localName4 = elementDecl.name || elementDecl.refName || "element";
3987
+ const bare = localName4.includes(":") ? localName4.split(":")[1] : localName4;
3372
3988
  const ns = elementDecl.namespaceUri;
3373
3989
  if (!ns) return bare;
3374
3990
  const prefix = state.nsContext.getPrefix(ns);
@@ -3517,6 +4133,24 @@ function buildNodesFromContent(schema, contentNode, options, state) {
3517
4133
  function buildComplexTypeContent(schema, complexTypeDecl, options, state) {
3518
4134
  const content = getEffectiveContent(schema, complexTypeDecl);
3519
4135
  const attributes = getEffectiveAttributes(schema, complexTypeDecl);
4136
+ if (state.currentDepth >= options.maxDepth) {
4137
+ return {
4138
+ attributes: buildAttributesObject(schema, attributes, options, state),
4139
+ children: []
4140
+ };
4141
+ }
4142
+ const typeKey = complexTypeDecl.name || complexTypeDecl.qName;
4143
+ if (typeKey && state.visitedTypes.has(typeKey)) {
4144
+ return {
4145
+ attributes: buildAttributesObject(schema, attributes, options, state),
4146
+ children: []
4147
+ };
4148
+ }
4149
+ if (typeKey) {
4150
+ state.visitedTypes.add(typeKey);
4151
+ }
4152
+ const previousDepth = state.currentDepth;
4153
+ state.currentDepth += 1;
3520
4154
  let children = content ? buildNodesFromContent(schema, content, options, state) : [];
3521
4155
  if (options.mode === "minimal" && children.length === 0 && content) {
3522
4156
  children = buildRepresentativeNodesFromContent(
@@ -3526,6 +4160,10 @@ function buildComplexTypeContent(schema, complexTypeDecl, options, state) {
3526
4160
  state
3527
4161
  );
3528
4162
  }
4163
+ state.currentDepth = previousDepth;
4164
+ if (typeKey) {
4165
+ state.visitedTypes.delete(typeKey);
4166
+ }
3529
4167
  return {
3530
4168
  attributes: buildAttributesObject(schema, attributes, options, state),
3531
4169
  children
@@ -3604,7 +4242,10 @@ function selectRoot(schema, options = {}) {
3604
4242
  function generateXmlFromSchema(schema, options = {}, helpers = {}) {
3605
4243
  const normalizedOptions = {
3606
4244
  mode: options.mode === "full" ? "full" : "minimal",
3607
- includeOptionalAttributes: options.includeOptionalAttributes === true
4245
+ includeOptionalAttributes: options.includeOptionalAttributes === true,
4246
+ maxDepth: options.maxDepth ?? 3,
4247
+ maxChoiceBranches: options.maxChoiceBranches ?? 1,
4248
+ expandRepeatingElements: options.expandRepeatingElements ?? 2
3608
4249
  };
3609
4250
  const root = selectRoot(schema, options);
3610
4251
  if (!root) {
@@ -3617,7 +4258,9 @@ function generateXmlFromSchema(schema, options = {}, helpers = {}) {
3617
4258
  const state = {
3618
4259
  resolveAttributeGroup: helpers.resolveAttributeGroup,
3619
4260
  targetPrefix: options.targetPrefix || "tns",
3620
- nsContext
4261
+ nsContext,
4262
+ visitedTypes: /* @__PURE__ */ new Set(),
4263
+ currentDepth: 0
3621
4264
  };
3622
4265
  const [rootNode] = buildElementInstances(
3623
4266
  schema,
@@ -3720,6 +4363,80 @@ function generateSampleXml({ xsdText, options = {} } = {}) {
3720
4363
  });
3721
4364
  }
3722
4365
 
4366
+ // src/validation/wildcardValidator.js
4367
+ function namespaceMatches(elementNamespace, wildcardNamespace, targetNamespace) {
4368
+ if (!wildcardNamespace) return true;
4369
+ if (wildcardNamespace === "##any") return true;
4370
+ if (wildcardNamespace === "##targetNamespace") {
4371
+ return elementNamespace === targetNamespace;
4372
+ }
4373
+ if (wildcardNamespace === "##other") {
4374
+ return elementNamespace !== targetNamespace;
4375
+ }
4376
+ if (Array.isArray(wildcardNamespace)) {
4377
+ return wildcardNamespace.includes(elementNamespace);
4378
+ }
4379
+ return elementNamespace === wildcardNamespace;
4380
+ }
4381
+ function isExcludedByNotNamespace(elementNamespace, notNamespace) {
4382
+ if (!notNamespace || notNamespace.length === 0) return false;
4383
+ return notNamespace.includes(elementNamespace);
4384
+ }
4385
+ function isExcludedByNotQName(qName, notQName) {
4386
+ if (!notQName || notQName.length === 0) return false;
4387
+ return notQName.includes(qName);
4388
+ }
4389
+ function buildQName(localName4, namespaceUri4) {
4390
+ if (!namespaceUri4 || namespaceUri4 === "") {
4391
+ return localName4;
4392
+ }
4393
+ return `{${namespaceUri4}}${localName4}`;
4394
+ }
4395
+ function elementMatchesWildcard(elementLocalName, elementNamespace, wildcardNode, targetNamespace) {
4396
+ if (!wildcardNode || wildcardNode.kind !== "any") {
4397
+ return false;
4398
+ }
4399
+ if (!namespaceMatches(elementNamespace, wildcardNode.namespace, targetNamespace)) {
4400
+ return false;
4401
+ }
4402
+ if (isExcludedByNotNamespace(elementNamespace, wildcardNode.notNamespace)) {
4403
+ return false;
4404
+ }
4405
+ const qName = buildQName(elementLocalName, elementNamespace);
4406
+ if (isExcludedByNotQName(qName, wildcardNode.notQName)) {
4407
+ return false;
4408
+ }
4409
+ return true;
4410
+ }
4411
+ function attributeMatchesWildcard(attrLocalName, attrNamespace, wildcardNode, targetNamespace) {
4412
+ if (!wildcardNode || wildcardNode.kind !== "anyAttribute") {
4413
+ return false;
4414
+ }
4415
+ if (!namespaceMatches(attrNamespace, wildcardNode.namespace, targetNamespace)) {
4416
+ return false;
4417
+ }
4418
+ if (isExcludedByNotNamespace(attrNamespace, wildcardNode.notNamespace)) {
4419
+ return false;
4420
+ }
4421
+ const qName = buildQName(attrLocalName, attrNamespace);
4422
+ if (isExcludedByNotQName(qName, wildcardNode.notQName)) {
4423
+ return false;
4424
+ }
4425
+ return true;
4426
+ }
4427
+ function normalizeProcessContents(processContents) {
4428
+ if (processContents === "lax" || processContents === "skip") {
4429
+ return processContents;
4430
+ }
4431
+ return "strict";
4432
+ }
4433
+ function isStrictWildcardValidation(processContents) {
4434
+ return normalizeProcessContents(processContents) === "strict";
4435
+ }
4436
+ function shouldSkipWildcardValidation(processContents) {
4437
+ return normalizeProcessContents(processContents) === "skip";
4438
+ }
4439
+
3723
4440
  // src/validation/structureValidator.js
3724
4441
  function elementChildren2(xmlNode) {
3725
4442
  return Array.from(xmlNode?.children || []).filter((child) => child.nodeType === 1);
@@ -3789,6 +4506,7 @@ function isSimpleContentComplexType(complexTypeDecl) {
3789
4506
  function validateAttributes(xmlNode, attributes, context) {
3790
4507
  const { schema, createIssue: createIssue2, ISSUE_CODES: ISSUE_CODES2, issues, pathParts, validateAttributeValue: validateAttributeValue2 } = context;
3791
4508
  const allowed = /* @__PURE__ */ new Map();
4509
+ let anyAttributeWildcard = null;
3792
4510
  for (const attr of attributes || []) {
3793
4511
  if (!attr) continue;
3794
4512
  if (attr.kind === "attribute") {
@@ -3800,6 +4518,8 @@ function validateAttributes(xmlNode, attributes, context) {
3800
4518
  const group = context.resolveAttributeGroup?.(attr.refName);
3801
4519
  if (!group) continue;
3802
4520
  validateAttributes(xmlNode, group.attributes || [], context);
4521
+ } else if (attr.kind === "anyAttribute") {
4522
+ anyAttributeWildcard = attr;
3803
4523
  }
3804
4524
  }
3805
4525
  for (const attrDecl of allowed.values()) {
@@ -3845,6 +4565,15 @@ function validateAttributes(xmlNode, attributes, context) {
3845
4565
  continue;
3846
4566
  }
3847
4567
  if (!allowed.has(attr.name)) {
4568
+ if (anyAttributeWildcard) {
4569
+ const attrLocalName = attr.localName || attr.name.split(":")[1] || attr.name;
4570
+ const attrNamespace = attr.namespaceURI || null;
4571
+ if (attributeMatchesWildcard(attrLocalName, attrNamespace, anyAttributeWildcard, schema.targetNamespace)) {
4572
+ if (!shouldSkipWildcardValidation(anyAttributeWildcard.processContents)) {
4573
+ }
4574
+ continue;
4575
+ }
4576
+ }
3848
4577
  issues.push(
3849
4578
  createIssue2({
3850
4579
  code: ISSUE_CODES2.XML_UNEXPECTED_ATTRIBUTE,
@@ -4262,7 +4991,16 @@ function validateContentModel(children, modelNode, context, pathParts, startInde
4262
4991
  return validateAll(children, startIndex, modelNode, context, pathParts, silent);
4263
4992
  case "any":
4264
4993
  if (startIndex < children.length) {
4265
- return { nextIndex: startIndex + 1, matched: true, matchedAny: true };
4994
+ const childNode = children[startIndex];
4995
+ const childLocalName = localName(childNode);
4996
+ const childNamespace = namespaceUri(childNode);
4997
+ if (elementMatchesWildcard(childLocalName, childNamespace, modelNode, context.schema.targetNamespace)) {
4998
+ if (isStrictWildcardValidation(modelNode.processContents)) {
4999
+ validateElementDecl(childNode, { name: childLocalName, typeName: null }, context, [...pathParts, childLocalName]);
5000
+ } else if (!shouldSkipWildcardValidation(modelNode.processContents)) {
5001
+ }
5002
+ return { nextIndex: startIndex + 1, matched: true, matchedAny: true };
5003
+ }
4266
5004
  }
4267
5005
  return { nextIndex: startIndex, matched: true, matchedAny: false };
4268
5006
  default:
@@ -4270,6 +5008,461 @@ function validateContentModel(children, modelNode, context, pathParts, startInde
4270
5008
  }
4271
5009
  }
4272
5010
 
5011
+ // src/utils/xpathEvaluator.js
5012
+ function nodeMatchesQName(schema, node, qName) {
5013
+ if (!node || !qName) return false;
5014
+ const parsed = parseQName(qName);
5015
+ const expectedNs = resolveNamespaceUri(schema, parsed.prefix);
5016
+ const nodeLocal = node.localName || node.nodeName || null;
5017
+ const nodeNs = node.namespaceURI || null;
5018
+ if (parsed.prefix) {
5019
+ let nsToCompare = expectedNs || null;
5020
+ if (!nsToCompare) {
5021
+ if (typeof node.lookupNamespaceURI === "function") {
5022
+ try {
5023
+ nsToCompare = node.lookupNamespaceURI(parsed.prefix) || null;
5024
+ } catch (e) {
5025
+ nsToCompare = null;
5026
+ }
5027
+ }
5028
+ if (!nsToCompare && node.prefix) {
5029
+ return nodeLocal === parsed.localName && node.prefix === parsed.prefix;
5030
+ }
5031
+ }
5032
+ return nodeLocal === parsed.localName && (nodeNs || null) === (nsToCompare || null);
5033
+ }
5034
+ return nodeLocal === parsed.localName;
5035
+ }
5036
+ function collectDescendants(node, predicate) {
5037
+ const matches = [];
5038
+ function traverse(n) {
5039
+ if (!n || n.nodeType !== 1) return;
5040
+ if (predicate(n)) matches.push(n);
5041
+ for (const child of Array.from(n.childNodes || [])) {
5042
+ traverse(child);
5043
+ }
5044
+ }
5045
+ traverse(node);
5046
+ return matches;
5047
+ }
5048
+ function evaluateSelector(schema, startNodes, selectorXPath) {
5049
+ if (!selectorXPath || !Array.isArray(startNodes) || startNodes.length === 0) return [];
5050
+ let xpath = selectorXPath.trim();
5051
+ if (xpath.startsWith("./")) xpath = xpath.slice(2);
5052
+ if (xpath === "." || xpath === "") return startNodes;
5053
+ if (xpath.includes("//")) {
5054
+ return evaluateSelectorWithDescendant(schema, startNodes, xpath);
5055
+ }
5056
+ const segments = xpath.split("/");
5057
+ let nodes = startNodes;
5058
+ for (const raw of segments) {
5059
+ if (!raw || raw === ".") continue;
5060
+ const m = raw.match(/^([^\[]+)(?:\[(.+)\])?$/);
5061
+ if (!m) return [];
5062
+ const step = m[1];
5063
+ const predicate = m[2] || null;
5064
+ if (step === "*") {
5065
+ nodes = nodes.flatMap((n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1));
5066
+ } else if (step.startsWith("@")) {
5067
+ return [];
5068
+ } else {
5069
+ nodes = nodes.flatMap(
5070
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => {
5071
+ return nodeMatchesQName(schema, c, step);
5072
+ })
5073
+ );
5074
+ if (predicate && nodes.length) {
5075
+ const num = Number(predicate);
5076
+ if (Number.isInteger(num) && num > 0) {
5077
+ const idx = num - 1;
5078
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5079
+ } else {
5080
+ const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5081
+ if (attrMatch) {
5082
+ const attrName = attrMatch[1];
5083
+ const attrValue = attrMatch[2];
5084
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5085
+ } else {
5086
+ nodes = [];
5087
+ }
5088
+ }
5089
+ }
5090
+ }
5091
+ }
5092
+ return nodes;
5093
+ }
5094
+ function evaluateSelectorWithDescendant(schema, startNodes, xpath) {
5095
+ const fullParts = xpath.split(/\/\//);
5096
+ let nodes = startNodes;
5097
+ for (let partIdx = 0; partIdx < fullParts.length; partIdx++) {
5098
+ const part = fullParts[partIdx].trim();
5099
+ if (!part) continue;
5100
+ if (partIdx === 0) {
5101
+ if (part !== ".") {
5102
+ const segments = part.split("/");
5103
+ for (const seg of segments) {
5104
+ if (!seg || seg === ".") continue;
5105
+ const m = seg.match(/^([^\[]+)(?:\[(.+)\])?$/);
5106
+ if (!m) return [];
5107
+ const step = m[1];
5108
+ const predicate = m[2] || null;
5109
+ if (step === "*") {
5110
+ nodes = nodes.flatMap((n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1));
5111
+ } else if (step.startsWith("@")) {
5112
+ return [];
5113
+ } else {
5114
+ nodes = nodes.flatMap(
5115
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => nodeMatchesQName(schema, c, step))
5116
+ );
5117
+ if (predicate && nodes.length) {
5118
+ const num = Number(predicate);
5119
+ if (Number.isInteger(num) && num > 0) {
5120
+ const idx = num - 1;
5121
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5122
+ } else {
5123
+ const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5124
+ if (attrMatch) {
5125
+ const attrName = attrMatch[1];
5126
+ const attrValue = attrMatch[2];
5127
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5128
+ } else {
5129
+ nodes = [];
5130
+ }
5131
+ }
5132
+ }
5133
+ }
5134
+ }
5135
+ }
5136
+ } else {
5137
+ const segments = part.split("/");
5138
+ for (let segIdx = 0; segIdx < segments.length; segIdx++) {
5139
+ const segment = segments[segIdx];
5140
+ if (!segment || segment === ".") continue;
5141
+ const m = segment.match(/^([^\[]+)(?:\[(.+)\])?$/);
5142
+ if (!m) return [];
5143
+ const step = m[1];
5144
+ const predicate = m[2] || null;
5145
+ if (segIdx === 0) {
5146
+ const descendants = [];
5147
+ for (const node of nodes) {
5148
+ const matches = collectDescendants(node, (n) => {
5149
+ if (step === "*") return true;
5150
+ if (step.startsWith("@")) return false;
5151
+ return nodeMatchesQName(schema, n, step);
5152
+ });
5153
+ descendants.push(...matches);
5154
+ }
5155
+ nodes = descendants;
5156
+ if (predicate && nodes.length) {
5157
+ const predicateMatch = predicate.match(/^\[(.+)\]$/);
5158
+ if (predicateMatch) {
5159
+ const pred = predicateMatch[1];
5160
+ const num = Number(pred);
5161
+ if (Number.isInteger(num) && num > 0) {
5162
+ const idx = num - 1;
5163
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5164
+ } else {
5165
+ const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5166
+ if (attrMatch) {
5167
+ const attrName = attrMatch[1];
5168
+ const attrValue = attrMatch[2];
5169
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5170
+ } else {
5171
+ nodes = [];
5172
+ }
5173
+ }
5174
+ }
5175
+ }
5176
+ } else {
5177
+ nodes = nodes.flatMap(
5178
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1).filter((c) => {
5179
+ if (step === "*") return true;
5180
+ if (step.startsWith("@")) return false;
5181
+ return nodeMatchesQName(schema, c, step);
5182
+ })
5183
+ );
5184
+ if (predicate && nodes.length) {
5185
+ const predicateMatch = predicate.match(/^\[(.+)\]$/);
5186
+ if (predicateMatch) {
5187
+ const pred = predicateMatch[1];
5188
+ const num = Number(pred);
5189
+ if (Number.isInteger(num) && num > 0) {
5190
+ const idx = num - 1;
5191
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5192
+ } else {
5193
+ const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5194
+ if (attrMatch) {
5195
+ const attrName = attrMatch[1];
5196
+ const attrValue = attrMatch[2];
5197
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5198
+ } else {
5199
+ nodes = [];
5200
+ }
5201
+ }
5202
+ }
5203
+ }
5204
+ }
5205
+ }
5206
+ }
5207
+ if (!nodes.length && partIdx < fullParts.length - 1) {
5208
+ return [];
5209
+ }
5210
+ }
5211
+ return nodes;
5212
+ }
5213
+ function evaluateField(schema, contextNode, fieldXPath) {
5214
+ if (!fieldXPath || !contextNode) return null;
5215
+ let xpath = fieldXPath.trim();
5216
+ if (xpath.startsWith("./")) xpath = xpath.slice(2);
5217
+ if (xpath === ".") return (contextNode.textContent || "").trim() || null;
5218
+ if (xpath.startsWith("@")) {
5219
+ const attr = xpath.slice(1);
5220
+ return contextNode.getAttribute(attr) ?? null;
5221
+ }
5222
+ if (xpath.includes("//")) {
5223
+ return evaluateFieldWithDescendant(schema, contextNode, xpath);
5224
+ }
5225
+ const segments = xpath.split("/");
5226
+ let nodes = [contextNode];
5227
+ for (let i = 0; i < segments.length; i += 1) {
5228
+ const raw = segments[i];
5229
+ if (!raw || raw === ".") continue;
5230
+ const m = raw.match(/^([^\[]+)(?:\[(.+)\])?$/);
5231
+ if (!m) return null;
5232
+ const step = m[1];
5233
+ const predicate = m[2] || null;
5234
+ if (step.startsWith("@")) {
5235
+ if (i !== segments.length - 1) return null;
5236
+ return nodes[0]?.getAttribute(step.slice(1)) ?? null;
5237
+ }
5238
+ nodes = nodes.flatMap(
5239
+ (n) => Array.from(n.childNodes || []).filter((c) => c.nodeType === 1 && nodeMatchesQName(schema, c, step))
5240
+ );
5241
+ if (!nodes.length) return null;
5242
+ if (predicate) {
5243
+ const num = Number(predicate);
5244
+ if (Number.isInteger(num) && num > 0) {
5245
+ const idx = num - 1;
5246
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5247
+ } else {
5248
+ const attrMatch = predicate.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5249
+ if (attrMatch) {
5250
+ const attrName = attrMatch[1];
5251
+ const attrValue = attrMatch[2];
5252
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5253
+ } else {
5254
+ return null;
5255
+ }
5256
+ }
5257
+ }
5258
+ }
5259
+ const v = nodes[0];
5260
+ if (!v) return null;
5261
+ return (v.textContent || "").trim() || null;
5262
+ }
5263
+ function evaluateFieldWithDescendant(schema, contextNode, xpath) {
5264
+ const parts = xpath.split(/\/\//);
5265
+ let nodes = [contextNode];
5266
+ for (let i = 0; i < parts.length; i++) {
5267
+ const part = parts[i].trim();
5268
+ if (!part) continue;
5269
+ if (i === 0) {
5270
+ if (part !== "." && part !== "") {
5271
+ const val = evaluateField(schema, nodes[0], part);
5272
+ if (val !== null) return val;
5273
+ nodes = [];
5274
+ }
5275
+ } else {
5276
+ const m = part.match(/^([^\[]+)(?:\[(.+)\])?/);
5277
+ if (!m) return null;
5278
+ const step = m[1];
5279
+ const predicate = part.slice(m[0].length);
5280
+ if (step.startsWith("@")) {
5281
+ const attrName = step.slice(1);
5282
+ for (const node of nodes) {
5283
+ const descendants2 = collectDescendants(node, () => true);
5284
+ if (descendants2.length) {
5285
+ return descendants2[0]?.getAttribute(attrName) ?? null;
5286
+ }
5287
+ }
5288
+ return null;
5289
+ }
5290
+ const descendants = [];
5291
+ for (const node of nodes) {
5292
+ descendants.push(
5293
+ ...collectDescendants(node, (n) => {
5294
+ if (step === "*") return true;
5295
+ return nodeMatchesQName(schema, n, step);
5296
+ })
5297
+ );
5298
+ }
5299
+ nodes = descendants;
5300
+ if (!nodes.length) return null;
5301
+ if (predicate) {
5302
+ const predicateMatch = predicate.match(/^\[(.+)\]$/);
5303
+ if (predicateMatch) {
5304
+ const pred = predicateMatch[1];
5305
+ const num = Number(pred);
5306
+ if (Number.isInteger(num) && num > 0) {
5307
+ const idx = num - 1;
5308
+ nodes = nodes.length > idx ? [nodes[idx]] : [];
5309
+ } else {
5310
+ const attrMatch = pred.match(/^@([A-Za-z_][\w.-]*)=['"](.*)['"]$/);
5311
+ if (attrMatch) {
5312
+ const attrName = attrMatch[1];
5313
+ const attrValue = attrMatch[2];
5314
+ nodes = nodes.filter((n) => (n.getAttribute(attrName) || "") === attrValue);
5315
+ }
5316
+ }
5317
+ }
5318
+ }
5319
+ if (nodes.length) {
5320
+ const v = nodes[0];
5321
+ return (v.textContent || "").trim() || null;
5322
+ }
5323
+ }
5324
+ }
5325
+ return null;
5326
+ }
5327
+
5328
+ // src/validation/identityConstraintValidator.js
5329
+ function localName2(node) {
5330
+ return node?.localName || node?.nodeName || null;
5331
+ }
5332
+ function namespaceUri2(node) {
5333
+ return node?.namespaceURI || null;
5334
+ }
5335
+ function collectOwnerXmlNodes(xmlRoot, ownerName, ownerNamespaceUri) {
5336
+ const matches = [];
5337
+ function traverse(node) {
5338
+ if (!node || node.nodeType !== 1) return;
5339
+ if (localName2(node) === ownerName && (ownerNamespaceUri == null || ownerNamespaceUri === namespaceUri2(node))) {
5340
+ matches.push(node);
5341
+ }
5342
+ for (const child of Array.from(node.children || [])) {
5343
+ traverse(child);
5344
+ }
5345
+ }
5346
+ traverse(xmlRoot);
5347
+ return matches;
5348
+ }
5349
+ function getConstraintOwnerNodes(schema, xmlRoot, constraint) {
5350
+ if (!constraint.ownerName) {
5351
+ return [xmlRoot];
5352
+ }
5353
+ return collectOwnerXmlNodes(
5354
+ xmlRoot,
5355
+ constraint.ownerName,
5356
+ constraint.ownerNamespaceUri
5357
+ );
5358
+ }
5359
+ function validateIdentityConstraints(schema, xmlRoot, getNodeLocation) {
5360
+ const issues = [];
5361
+ const keySets = /* @__PURE__ */ new Map();
5362
+ function buildKeySet(constraint) {
5363
+ if (keySets.has(constraint.name)) {
5364
+ return keySets.get(constraint.name);
5365
+ }
5366
+ const set = /* @__PURE__ */ new Set();
5367
+ const ownerNodes = getConstraintOwnerNodes(schema, xmlRoot, constraint);
5368
+ for (const ownerNode of ownerNodes) {
5369
+ const selected = evaluateSelector(schema, [ownerNode], constraint.selector?.xpath);
5370
+ for (const selectedNode of selected) {
5371
+ const tuple = constraint.fields.map((field) => evaluateField(schema, selectedNode, field.xpath));
5372
+ set.add(JSON.stringify(tuple));
5373
+ }
5374
+ }
5375
+ keySets.set(constraint.name, set);
5376
+ return set;
5377
+ }
5378
+ for (const constraint of schema.identityConstraints || []) {
5379
+ const ownerNodes = getConstraintOwnerNodes(schema, xmlRoot, constraint);
5380
+ if (!ownerNodes.length) {
5381
+ continue;
5382
+ }
5383
+ const valueIndex = /* @__PURE__ */ new Map();
5384
+ const referenceKeyConstraint = schema.identityConstraints.find(
5385
+ (item) => item.kind === "key" && item.name === parseQName(constraint.refer || "").localName
5386
+ );
5387
+ const referenceKeySet = constraint.kind === "keyref" && referenceKeyConstraint ? buildKeySet(referenceKeyConstraint) : null;
5388
+ for (const ownerNode of ownerNodes) {
5389
+ const selected = evaluateSelector(schema, [ownerNode], constraint.selector?.xpath);
5390
+ for (const selectedNode of selected) {
5391
+ const tuple = constraint.fields.map((field) => evaluateField(schema, selectedNode, field.xpath));
5392
+ const tupleKey = JSON.stringify(tuple);
5393
+ const rawLocation = getNodeLocation ? getNodeLocation(selectedNode) : null;
5394
+ const location = rawLocation || { line: constraint.line || 1, column: constraint.column || 1 };
5395
+ if (tuple.some((value) => value == null || value === "")) {
5396
+ if (constraint.kind === "key") {
5397
+ issues.push(
5398
+ createIssue({
5399
+ code: ISSUE_CODES.XML_KEY_NULL_VIOLATION,
5400
+ severity: "error",
5401
+ message: `xs:key '${constraint.name}' requires non-empty values for all fields.`,
5402
+ line: location.line,
5403
+ column: location.column,
5404
+ path: constraint.path,
5405
+ source: "xml",
5406
+ nodeKind: "element",
5407
+ name: constraint.name,
5408
+ details: {
5409
+ selector: constraint.selector?.xpath,
5410
+ fields: constraint.fields.map((field) => field.xpath)
5411
+ }
5412
+ })
5413
+ );
5414
+ }
5415
+ }
5416
+ if (constraint.kind === "key" || constraint.kind === "unique") {
5417
+ if (valueIndex.has(tupleKey)) {
5418
+ issues.push(
5419
+ createIssue({
5420
+ code: constraint.kind === "key" ? ISSUE_CODES.XML_KEY_VIOLATION : ISSUE_CODES.XML_UNIQUE_VIOLATION,
5421
+ severity: "error",
5422
+ message: `Duplicate ${constraint.kind} value for '${constraint.name}'.`,
5423
+ line: location.line,
5424
+ column: location.column,
5425
+ path: constraint.path,
5426
+ source: "xml",
5427
+ nodeKind: "element",
5428
+ name: constraint.name,
5429
+ details: {
5430
+ selector: constraint.selector?.xpath,
5431
+ fields: constraint.fields.map((field) => field.xpath)
5432
+ }
5433
+ })
5434
+ );
5435
+ }
5436
+ valueIndex.set(tupleKey, true);
5437
+ }
5438
+ if (constraint.kind === "keyref" && referenceKeySet) {
5439
+ if (!referenceKeySet.has(tupleKey)) {
5440
+ issues.push(
5441
+ createIssue({
5442
+ code: ISSUE_CODES.XML_KEYREF_VIOLATION,
5443
+ severity: "error",
5444
+ message: `xs:keyref '${constraint.name}' references a missing key value.`,
5445
+ line: location.line,
5446
+ column: location.column,
5447
+ path: constraint.path,
5448
+ source: "xml",
5449
+ nodeKind: "element",
5450
+ name: constraint.name,
5451
+ details: {
5452
+ refer: constraint.refer,
5453
+ selector: constraint.selector?.xpath,
5454
+ fields: constraint.fields.map((field) => field.xpath)
5455
+ }
5456
+ })
5457
+ );
5458
+ }
5459
+ }
5460
+ }
5461
+ }
5462
+ }
5463
+ return issues;
5464
+ }
5465
+
4273
5466
  // src/validation/builtinTypeValidators.js
4274
5467
  function isIntegerString(value) {
4275
5468
  return /^[-+]?\d+$/.test(value);
@@ -4767,12 +5960,12 @@ function findAttributeValueOffset(tagText, attrName) {
4767
5960
  const end = tagText.indexOf(quoteChar, start);
4768
5961
  return end >= start ? start : -1;
4769
5962
  }
4770
- function findTextContentOffset(text, tagEndOffset, localName3) {
5963
+ function findTextContentOffset(text, tagEndOffset, localName4) {
4771
5964
  let i = tagEndOffset + 1;
4772
5965
  while (i < text.length && /\s/.test(text[i])) {
4773
5966
  i += 1;
4774
5967
  }
4775
- if (text.startsWith(`</${localName3}`, i) || text[i] === "<") {
5968
+ if (text.startsWith(`</${localName4}`, i) || text[i] === "<") {
4776
5969
  return -1;
4777
5970
  }
4778
5971
  return i < text.length ? i : -1;
@@ -4799,10 +5992,20 @@ function createXmlSourceLocator(xmlText, xmlDocument) {
4799
5992
  }
4800
5993
  };
4801
5994
  }
4802
- const orderedNodes = [
4803
- documentElement,
4804
- ...Array.from(documentElement.querySelectorAll("*"))
4805
- ];
5995
+ let orderedNodes = null;
5996
+ if (typeof documentElement.querySelectorAll === "function") {
5997
+ orderedNodes = [documentElement, ...Array.from(documentElement.querySelectorAll("*"))];
5998
+ } else {
5999
+ let collect = function(node) {
6000
+ if (!node || node.nodeType !== 1) return;
6001
+ orderedNodes.push(node);
6002
+ for (const child of Array.from(node.children || [])) {
6003
+ collect(child);
6004
+ }
6005
+ };
6006
+ orderedNodes = [];
6007
+ collect(documentElement);
6008
+ }
4806
6009
  let searchFrom = 0;
4807
6010
  for (const node of orderedNodes) {
4808
6011
  const expectedLocalName = getNodeLocalName(node);
@@ -4879,10 +6082,10 @@ function elementChildren3(xmlNode) {
4879
6082
  (child) => child.nodeType === 1
4880
6083
  );
4881
6084
  }
4882
- function localName2(node) {
6085
+ function localName3(node) {
4883
6086
  return node?.localName || node?.nodeName || null;
4884
6087
  }
4885
- function namespaceUri2(node) {
6088
+ function namespaceUri3(node) {
4886
6089
  return node?.namespaceURI || null;
4887
6090
  }
4888
6091
  function determineRootElement(schema, xmlRootName, xmlRootNs, options) {
@@ -4927,8 +6130,8 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
4927
6130
  }
4928
6131
  const locator = createXmlSourceLocator(xmlText, xmlParse.document);
4929
6132
  const xmlRoot = xmlParse.document.documentElement;
4930
- const xmlRootName = localName2(xmlRoot);
4931
- const xmlRootNs = namespaceUri2(xmlRoot);
6133
+ const xmlRootName = localName3(xmlRoot);
6134
+ const xmlRootNs = namespaceUri3(xmlRoot);
4932
6135
  const issues = [...parseIssues];
4933
6136
  if (!xmlRoot) {
4934
6137
  return {
@@ -5048,7 +6251,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
5048
6251
  const children2 = elementChildren3(xmlRoot);
5049
6252
  if (children2.length > 0) {
5050
6253
  for (const childNode of children2) {
5051
- const childName = localName2(childNode);
6254
+ const childName = localName3(childNode);
5052
6255
  issues.push(
5053
6256
  createIssue({
5054
6257
  code: ISSUE_CODES.XML_UNEXPECTED_ELEMENT,
@@ -5060,7 +6263,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
5060
6263
  nodeKind: "element",
5061
6264
  name: childName,
5062
6265
  details: {
5063
- namespaceUri: namespaceUri2(childNode)
6266
+ namespaceUri: namespaceUri3(childNode)
5064
6267
  }
5065
6268
  })
5066
6269
  );
@@ -5137,7 +6340,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
5137
6340
  if (result.nextIndex < children.length) {
5138
6341
  for (let i = result.nextIndex; i < children.length; i += 1) {
5139
6342
  const childNode = children[i];
5140
- const childName = localName2(childNode);
6343
+ const childName = localName3(childNode);
5141
6344
  issues.push(
5142
6345
  createIssue({
5143
6346
  code: ISSUE_CODES.XML_UNEXPECTED_ELEMENT,
@@ -5149,7 +6352,7 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
5149
6352
  nodeKind: "element",
5150
6353
  name: childName,
5151
6354
  details: {
5152
- namespaceUri: namespaceUri2(childNode)
6355
+ namespaceUri: namespaceUri3(childNode)
5153
6356
  }
5154
6357
  })
5155
6358
  );
@@ -5180,6 +6383,12 @@ function validateXmlAgainstSchema(schema, xmlText, options = {}, helpers = {}) {
5180
6383
  );
5181
6384
  }
5182
6385
  }
6386
+ const identityConstraintIssues = validateIdentityConstraints(
6387
+ schema,
6388
+ xmlRoot,
6389
+ locator.getNodeLocation
6390
+ );
6391
+ issues.push(...identityConstraintIssues);
5183
6392
  return {
5184
6393
  data: {
5185
6394
  xmlValid: !issues.some((issue) => issue.severity === "error")