uss-xsd-engine 0.1.0-rc.2 → 0.1.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.0-rc.2
2
+ * uss-xsd-engine v0.1.1
3
3
  * (c) 2026 Bernard Mumble
4
4
  * MIT License
5
5
  */
@@ -583,6 +583,33 @@ function lookupInImportedSchemas(bucketName, schema, namespaceUri3, localName3,
583
583
  }
584
584
  return null;
585
585
  }
586
+ function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName3, visited = /* @__PURE__ */ new Set()) {
587
+ if (!schema || !localName3) return null;
588
+ if (visited.has(schema)) return null;
589
+ visited.add(schema);
590
+ const targetNs = schema.targetNamespace || null;
591
+ for (const importedSchema of schema.importedSchemas || []) {
592
+ if (!importedSchema) continue;
593
+ const importedNs = importedSchema.targetNamespace || null;
594
+ if (importedNs === targetNs) {
595
+ const direct = lookupInSchemaBucket(
596
+ bucketName,
597
+ importedSchema,
598
+ importedNs,
599
+ localName3
600
+ );
601
+ if (direct) return direct;
602
+ }
603
+ const nested = lookupInImportedSchemasForUnprefixed(
604
+ bucketName,
605
+ importedSchema,
606
+ localName3,
607
+ visited
608
+ );
609
+ if (nested) return nested;
610
+ }
611
+ return null;
612
+ }
586
613
  function lookupByQName(bucketName, schema, name) {
587
614
  if (!schema || !name) return null;
588
615
  const parsed = parseQName(name);
@@ -615,6 +642,12 @@ function lookupByQName(bucketName, schema, name) {
615
642
  localName3
616
643
  );
617
644
  if (hostNamespaceDecl) return hostNamespaceDecl;
645
+ const importedSameNamespaceDecl = lookupInImportedSchemasForUnprefixed(
646
+ bucketName,
647
+ schema,
648
+ localName3
649
+ );
650
+ if (importedSameNamespaceDecl) return importedSameNamespaceDecl;
618
651
  }
619
652
  return null;
620
653
  }
@@ -1542,6 +1575,111 @@ function isImportNamespaceCompatible(ref, importedSchema) {
1542
1575
  }
1543
1576
  return (declaredNs || null) === (importedNs || null);
1544
1577
  }
1578
+ function normalizeSchemaPath(value) {
1579
+ if (!value || typeof value !== "string") return null;
1580
+ const trimmed = value.trim();
1581
+ if (!trimmed) return null;
1582
+ return trimmed.replace(/\\/g, "/").replace(/\/+/g, "/");
1583
+ }
1584
+ function getSchemaPathBasename(value) {
1585
+ const normalized = normalizeSchemaPath(value);
1586
+ if (!normalized) return null;
1587
+ const parts = normalized.split("/");
1588
+ return parts[parts.length - 1] || null;
1589
+ }
1590
+ function getExternalDocumentEntries(externalDocuments) {
1591
+ return Object.entries(externalDocuments || {}).map(([key, text]) => ({
1592
+ key,
1593
+ normalizedKey: normalizeSchemaPath(key),
1594
+ basename: getSchemaPathBasename(key),
1595
+ text
1596
+ }));
1597
+ }
1598
+ function getDeclaredTargetNamespaceFromText(xsdText) {
1599
+ if (typeof xsdText !== "string" || !xsdText.trim()) {
1600
+ return null;
1601
+ }
1602
+ try {
1603
+ const parser = new DOMParser();
1604
+ const doc = parser.parseFromString(xsdText, "application/xml");
1605
+ const parserError = doc.querySelector("parsererror");
1606
+ if (parserError) return null;
1607
+ const root = getSchemaRoot(doc);
1608
+ if (!root) return null;
1609
+ return root.hasAttribute("targetNamespace") ? root.getAttribute("targetNamespace") : null;
1610
+ } catch {
1611
+ return null;
1612
+ }
1613
+ }
1614
+ function resolveExternalDocument(ref, externalDocuments) {
1615
+ const entries = getExternalDocumentEntries(externalDocuments);
1616
+ const requestedLocation = ref?.schemaLocation || null;
1617
+ const normalizedRequestedLocation = normalizeSchemaPath(requestedLocation);
1618
+ const requestedBasename = getSchemaPathBasename(requestedLocation);
1619
+ if (requestedLocation && Object.prototype.hasOwnProperty.call(externalDocuments, requestedLocation)) {
1620
+ return {
1621
+ kind: "exact",
1622
+ entry: {
1623
+ key: requestedLocation,
1624
+ normalizedKey: normalizedRequestedLocation,
1625
+ basename: requestedBasename,
1626
+ text: externalDocuments[requestedLocation]
1627
+ },
1628
+ matches: []
1629
+ };
1630
+ }
1631
+ if (normalizedRequestedLocation) {
1632
+ const normalizedMatches = entries.filter(
1633
+ (entry) => entry.normalizedKey === normalizedRequestedLocation
1634
+ );
1635
+ if (normalizedMatches.length === 1) {
1636
+ return {
1637
+ kind: "normalized",
1638
+ entry: normalizedMatches[0],
1639
+ matches: normalizedMatches
1640
+ };
1641
+ }
1642
+ }
1643
+ if (requestedBasename) {
1644
+ const basenameMatches = entries.filter(
1645
+ (entry) => entry.basename === requestedBasename
1646
+ );
1647
+ if (basenameMatches.length === 1) {
1648
+ return {
1649
+ kind: "basename",
1650
+ entry: basenameMatches[0],
1651
+ matches: basenameMatches
1652
+ };
1653
+ }
1654
+ }
1655
+ if (ref?.kind === "import" && ref.namespace) {
1656
+ const namespaceMatches = entries.filter((entry) => {
1657
+ const declaredTargetNamespace = getDeclaredTargetNamespaceFromText(
1658
+ entry.text
1659
+ );
1660
+ return (declaredTargetNamespace || null) === (ref.namespace || null);
1661
+ });
1662
+ if (namespaceMatches.length === 1) {
1663
+ return {
1664
+ kind: "namespace",
1665
+ entry: namespaceMatches[0],
1666
+ matches: namespaceMatches
1667
+ };
1668
+ }
1669
+ if (namespaceMatches.length > 1) {
1670
+ return {
1671
+ kind: "ambiguous-namespace",
1672
+ entry: null,
1673
+ matches: namespaceMatches
1674
+ };
1675
+ }
1676
+ }
1677
+ return {
1678
+ kind: "not-found",
1679
+ entry: null,
1680
+ matches: []
1681
+ };
1682
+ }
1545
1683
  function buildSchemaModel(doc, options = {}) {
1546
1684
  const issues = [];
1547
1685
  const schema = createEmptySchemaModel();
@@ -1740,11 +1878,34 @@ function buildSchemaModel(doc, options = {}) {
1740
1878
  const imports = schema.externalRefs.imports || [];
1741
1879
  for (const ref of [...includes, ...imports]) {
1742
1880
  if (!ref.schemaLocation) continue;
1743
- const visitKey = ref.kind === "include" && schema.targetNamespace ? `${ref.schemaLocation}::include::${schema.targetNamespace}` : ref.schemaLocation;
1881
+ const resolution = resolveExternalDocument(ref, externalDocuments);
1882
+ if (resolution.kind === "ambiguous-namespace") {
1883
+ issues.push(
1884
+ createIssue({
1885
+ code: ISSUE_CODES.XSD_IMPORT_NOT_PROVIDED,
1886
+ severity: "error",
1887
+ message: `Multiple provided schemas match xs:import namespace '${ref.namespace || ""}'. Unable to determine which schema to use.`,
1888
+ line: ref.line,
1889
+ column: ref.column,
1890
+ path: ref.path,
1891
+ source: "xsd",
1892
+ nodeKind: ref.kind,
1893
+ details: {
1894
+ schemaLocation: ref.schemaLocation,
1895
+ namespace: ref.namespace,
1896
+ matchingKeys: resolution.matches.map((match) => match.key)
1897
+ }
1898
+ })
1899
+ );
1900
+ continue;
1901
+ }
1902
+ const resolvedEntry = resolution.entry;
1903
+ const resolvedSchemaKey = resolvedEntry?.key || ref.schemaLocation;
1904
+ const visitKey = ref.kind === "include" && schema.targetNamespace ? `${resolvedSchemaKey}::include::${schema.targetNamespace}` : resolvedSchemaKey;
1744
1905
  if (visited.has(visitKey)) {
1745
1906
  continue;
1746
1907
  }
1747
- const externalXsdText = externalDocuments[ref.schemaLocation];
1908
+ const externalXsdText = resolvedEntry?.text || null;
1748
1909
  if (!externalXsdText) {
1749
1910
  issues.push(
1750
1911
  createIssue({
@@ -1787,9 +1948,6 @@ function buildSchemaModel(doc, options = {}) {
1787
1948
  ...shouldApplyChameleonInclude ? { _overrideTargetNamespace: schema.targetNamespace } : {}
1788
1949
  });
1789
1950
  if (externalBuild.schema) {
1790
- if (ref.kind === "import") {
1791
- schema.importedSchemas.push(externalBuild.schema);
1792
- }
1793
1951
  if (ref.kind === "include") {
1794
1952
  if (!isIncludeNamespaceCompatible(schema, externalBuild.schema)) {
1795
1953
  issues.push(
@@ -1804,6 +1962,8 @@ function buildSchemaModel(doc, options = {}) {
1804
1962
  nodeKind: "include",
1805
1963
  details: {
1806
1964
  schemaLocation: ref.schemaLocation,
1965
+ resolvedSchemaKey,
1966
+ resolutionKind: resolution.kind,
1807
1967
  hostTargetNamespace: schema.targetNamespace || null,
1808
1968
  includedTargetNamespace: externalBuild.schema.targetNamespace || null,
1809
1969
  includedDeclaredTargetNamespace: externalDeclaredTargetNamespace,
@@ -1833,6 +1993,8 @@ function buildSchemaModel(doc, options = {}) {
1833
1993
  nodeKind: "import",
1834
1994
  details: {
1835
1995
  schemaLocation: ref.schemaLocation,
1996
+ resolvedSchemaKey,
1997
+ resolutionKind: resolution.kind,
1836
1998
  declaredNamespace: ref.namespace || null,
1837
1999
  importedTargetNamespace: externalBuild.schema.targetNamespace || null
1838
2000
  }
@@ -2171,12 +2333,72 @@ function runDefaultFixedDiagnostics(schema) {
2171
2333
  }
2172
2334
 
2173
2335
  // src/diagnostics/schemaImportDiagnostics.js
2336
+ function normalizeSchemaPath2(value) {
2337
+ if (!value || typeof value !== "string") return null;
2338
+ const trimmed = value.trim();
2339
+ if (!trimmed) return null;
2340
+ return trimmed.replace(/\\/g, "/").replace(/\/+/g, "/");
2341
+ }
2342
+ function getSchemaPathBasename2(value) {
2343
+ const normalized = normalizeSchemaPath2(value);
2344
+ if (!normalized) return null;
2345
+ const parts = normalized.split("/");
2346
+ return parts[parts.length - 1] || null;
2347
+ }
2348
+ function getExternalDocumentEntries2(externalDocuments) {
2349
+ return Object.entries(externalDocuments || {}).map(([key, text]) => ({
2350
+ key,
2351
+ normalizedKey: normalizeSchemaPath2(key),
2352
+ basename: getSchemaPathBasename2(key),
2353
+ text
2354
+ }));
2355
+ }
2356
+ function getDeclaredTargetNamespaceFromText2(xsdText) {
2357
+ if (typeof xsdText !== "string" || !xsdText.trim()) {
2358
+ return null;
2359
+ }
2360
+ try {
2361
+ const parser = new DOMParser();
2362
+ const doc = parser.parseFromString(xsdText, "application/xml");
2363
+ const parserError = doc.querySelector("parsererror");
2364
+ if (parserError) return null;
2365
+ const root = doc?.documentElement || null;
2366
+ if (!root || root.localName !== "schema") return null;
2367
+ return root.hasAttribute("targetNamespace") ? root.getAttribute("targetNamespace") : null;
2368
+ } catch {
2369
+ return null;
2370
+ }
2371
+ }
2372
+ function hasMatchingExternalDocument(ref, externalDocuments) {
2373
+ const entries = getExternalDocumentEntries2(externalDocuments);
2374
+ const requestedLocation = ref?.schemaLocation || null;
2375
+ const normalizedRequestedLocation = normalizeSchemaPath2(requestedLocation);
2376
+ const requestedBasename = getSchemaPathBasename2(requestedLocation);
2377
+ if (requestedLocation && Object.prototype.hasOwnProperty.call(externalDocuments, requestedLocation)) {
2378
+ return true;
2379
+ }
2380
+ if (normalizedRequestedLocation && entries.some((entry) => entry.normalizedKey === normalizedRequestedLocation)) {
2381
+ return true;
2382
+ }
2383
+ if (requestedBasename && entries.some((entry) => entry.basename === requestedBasename)) {
2384
+ return true;
2385
+ }
2386
+ if (ref?.kind === "import" && ref.namespace) {
2387
+ return entries.some((entry) => {
2388
+ const declaredTargetNamespace = getDeclaredTargetNamespaceFromText2(
2389
+ entry.text
2390
+ );
2391
+ return (declaredTargetNamespace || null) === (ref.namespace || null);
2392
+ });
2393
+ }
2394
+ return false;
2395
+ }
2174
2396
  function runImportDiagnostics(schema, options = {}) {
2175
2397
  const issues = [];
2176
2398
  const externalDocuments = options.externalDocuments || {};
2177
2399
  for (const ref of schema.externalRefs.includes || []) {
2178
2400
  if (!ref.schemaLocation) continue;
2179
- if (externalDocuments[ref.schemaLocation]) continue;
2401
+ if (hasMatchingExternalDocument(ref, externalDocuments)) continue;
2180
2402
  issues.push(
2181
2403
  createIssue({
2182
2404
  code: ISSUE_CODES.XSD_INCLUDE_NOT_PROVIDED,
@@ -2196,7 +2418,7 @@ function runImportDiagnostics(schema, options = {}) {
2196
2418
  }
2197
2419
  for (const ref of schema.externalRefs.imports || []) {
2198
2420
  if (!ref.schemaLocation) continue;
2199
- if (externalDocuments[ref.schemaLocation]) continue;
2421
+ if (hasMatchingExternalDocument(ref, externalDocuments)) continue;
2200
2422
  issues.push(
2201
2423
  createIssue({
2202
2424
  code: ISSUE_CODES.XSD_IMPORT_NOT_PROVIDED,
@@ -2407,7 +2629,7 @@ function runSchemaDiagnostics(schema, options = {}) {
2407
2629
  }
2408
2630
 
2409
2631
  // src/version.js
2410
- var ENGINE_VERSION = "v0.1.0-rc.2";
2632
+ var ENGINE_VERSION = "v0.1.1";
2411
2633
 
2412
2634
  // src/utils/result.js
2413
2635
  function summarizeIssues(issues = []) {
@@ -3404,6 +3626,14 @@ function generateXmlFromSchema(schema, options = {}, helpers = {}) {
3404
3626
  state,
3405
3627
  true
3406
3628
  );
3629
+ if (rootNode) {
3630
+ const finalNsAttrs = buildRootNamespaceAttributes(schema, root, state);
3631
+ rootNode.attributes = {
3632
+ ...finalNsAttrs,
3633
+ ...rootNode.attributes
3634
+ // preserve any existing attrs
3635
+ };
3636
+ }
3407
3637
  return {
3408
3638
  rootElementName: root.name,
3409
3639
  rootNode
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * uss-xsd-engine v0.1.0-rc.2
2
+ * uss-xsd-engine v0.1.1
3
3
  * (c) 2026 Bernard Mumble
4
4
  * MIT License
5
5
  */
@@ -610,6 +610,33 @@ var UssXsdEngine = (() => {
610
610
  }
611
611
  return null;
612
612
  }
613
+ function lookupInImportedSchemasForUnprefixed(bucketName, schema, localName3, visited = /* @__PURE__ */ new Set()) {
614
+ if (!schema || !localName3) return null;
615
+ if (visited.has(schema)) return null;
616
+ visited.add(schema);
617
+ const targetNs = schema.targetNamespace || null;
618
+ for (const importedSchema of schema.importedSchemas || []) {
619
+ if (!importedSchema) continue;
620
+ const importedNs = importedSchema.targetNamespace || null;
621
+ if (importedNs === targetNs) {
622
+ const direct = lookupInSchemaBucket(
623
+ bucketName,
624
+ importedSchema,
625
+ importedNs,
626
+ localName3
627
+ );
628
+ if (direct) return direct;
629
+ }
630
+ const nested = lookupInImportedSchemasForUnprefixed(
631
+ bucketName,
632
+ importedSchema,
633
+ localName3,
634
+ visited
635
+ );
636
+ if (nested) return nested;
637
+ }
638
+ return null;
639
+ }
613
640
  function lookupByQName(bucketName, schema, name) {
614
641
  if (!schema || !name) return null;
615
642
  const parsed = parseQName(name);
@@ -642,6 +669,12 @@ var UssXsdEngine = (() => {
642
669
  localName3
643
670
  );
644
671
  if (hostNamespaceDecl) return hostNamespaceDecl;
672
+ const importedSameNamespaceDecl = lookupInImportedSchemasForUnprefixed(
673
+ bucketName,
674
+ schema,
675
+ localName3
676
+ );
677
+ if (importedSameNamespaceDecl) return importedSameNamespaceDecl;
645
678
  }
646
679
  return null;
647
680
  }
@@ -1569,6 +1602,111 @@ var UssXsdEngine = (() => {
1569
1602
  }
1570
1603
  return (declaredNs || null) === (importedNs || null);
1571
1604
  }
1605
+ function normalizeSchemaPath(value) {
1606
+ if (!value || typeof value !== "string") return null;
1607
+ const trimmed = value.trim();
1608
+ if (!trimmed) return null;
1609
+ return trimmed.replace(/\\/g, "/").replace(/\/+/g, "/");
1610
+ }
1611
+ function getSchemaPathBasename(value) {
1612
+ const normalized = normalizeSchemaPath(value);
1613
+ if (!normalized) return null;
1614
+ const parts = normalized.split("/");
1615
+ return parts[parts.length - 1] || null;
1616
+ }
1617
+ function getExternalDocumentEntries(externalDocuments) {
1618
+ return Object.entries(externalDocuments || {}).map(([key, text]) => ({
1619
+ key,
1620
+ normalizedKey: normalizeSchemaPath(key),
1621
+ basename: getSchemaPathBasename(key),
1622
+ text
1623
+ }));
1624
+ }
1625
+ function getDeclaredTargetNamespaceFromText(xsdText) {
1626
+ if (typeof xsdText !== "string" || !xsdText.trim()) {
1627
+ return null;
1628
+ }
1629
+ try {
1630
+ const parser = new DOMParser();
1631
+ const doc = parser.parseFromString(xsdText, "application/xml");
1632
+ const parserError = doc.querySelector("parsererror");
1633
+ if (parserError) return null;
1634
+ const root = getSchemaRoot(doc);
1635
+ if (!root) return null;
1636
+ return root.hasAttribute("targetNamespace") ? root.getAttribute("targetNamespace") : null;
1637
+ } catch {
1638
+ return null;
1639
+ }
1640
+ }
1641
+ function resolveExternalDocument(ref, externalDocuments) {
1642
+ const entries = getExternalDocumentEntries(externalDocuments);
1643
+ const requestedLocation = ref?.schemaLocation || null;
1644
+ const normalizedRequestedLocation = normalizeSchemaPath(requestedLocation);
1645
+ const requestedBasename = getSchemaPathBasename(requestedLocation);
1646
+ if (requestedLocation && Object.prototype.hasOwnProperty.call(externalDocuments, requestedLocation)) {
1647
+ return {
1648
+ kind: "exact",
1649
+ entry: {
1650
+ key: requestedLocation,
1651
+ normalizedKey: normalizedRequestedLocation,
1652
+ basename: requestedBasename,
1653
+ text: externalDocuments[requestedLocation]
1654
+ },
1655
+ matches: []
1656
+ };
1657
+ }
1658
+ if (normalizedRequestedLocation) {
1659
+ const normalizedMatches = entries.filter(
1660
+ (entry) => entry.normalizedKey === normalizedRequestedLocation
1661
+ );
1662
+ if (normalizedMatches.length === 1) {
1663
+ return {
1664
+ kind: "normalized",
1665
+ entry: normalizedMatches[0],
1666
+ matches: normalizedMatches
1667
+ };
1668
+ }
1669
+ }
1670
+ if (requestedBasename) {
1671
+ const basenameMatches = entries.filter(
1672
+ (entry) => entry.basename === requestedBasename
1673
+ );
1674
+ if (basenameMatches.length === 1) {
1675
+ return {
1676
+ kind: "basename",
1677
+ entry: basenameMatches[0],
1678
+ matches: basenameMatches
1679
+ };
1680
+ }
1681
+ }
1682
+ if (ref?.kind === "import" && ref.namespace) {
1683
+ const namespaceMatches = entries.filter((entry) => {
1684
+ const declaredTargetNamespace = getDeclaredTargetNamespaceFromText(
1685
+ entry.text
1686
+ );
1687
+ return (declaredTargetNamespace || null) === (ref.namespace || null);
1688
+ });
1689
+ if (namespaceMatches.length === 1) {
1690
+ return {
1691
+ kind: "namespace",
1692
+ entry: namespaceMatches[0],
1693
+ matches: namespaceMatches
1694
+ };
1695
+ }
1696
+ if (namespaceMatches.length > 1) {
1697
+ return {
1698
+ kind: "ambiguous-namespace",
1699
+ entry: null,
1700
+ matches: namespaceMatches
1701
+ };
1702
+ }
1703
+ }
1704
+ return {
1705
+ kind: "not-found",
1706
+ entry: null,
1707
+ matches: []
1708
+ };
1709
+ }
1572
1710
  function buildSchemaModel(doc, options = {}) {
1573
1711
  const issues = [];
1574
1712
  const schema = createEmptySchemaModel();
@@ -1767,11 +1905,34 @@ var UssXsdEngine = (() => {
1767
1905
  const imports = schema.externalRefs.imports || [];
1768
1906
  for (const ref of [...includes, ...imports]) {
1769
1907
  if (!ref.schemaLocation) continue;
1770
- const visitKey = ref.kind === "include" && schema.targetNamespace ? `${ref.schemaLocation}::include::${schema.targetNamespace}` : ref.schemaLocation;
1908
+ const resolution = resolveExternalDocument(ref, externalDocuments);
1909
+ if (resolution.kind === "ambiguous-namespace") {
1910
+ issues.push(
1911
+ createIssue({
1912
+ code: ISSUE_CODES.XSD_IMPORT_NOT_PROVIDED,
1913
+ severity: "error",
1914
+ message: `Multiple provided schemas match xs:import namespace '${ref.namespace || ""}'. Unable to determine which schema to use.`,
1915
+ line: ref.line,
1916
+ column: ref.column,
1917
+ path: ref.path,
1918
+ source: "xsd",
1919
+ nodeKind: ref.kind,
1920
+ details: {
1921
+ schemaLocation: ref.schemaLocation,
1922
+ namespace: ref.namespace,
1923
+ matchingKeys: resolution.matches.map((match) => match.key)
1924
+ }
1925
+ })
1926
+ );
1927
+ continue;
1928
+ }
1929
+ const resolvedEntry = resolution.entry;
1930
+ const resolvedSchemaKey = resolvedEntry?.key || ref.schemaLocation;
1931
+ const visitKey = ref.kind === "include" && schema.targetNamespace ? `${resolvedSchemaKey}::include::${schema.targetNamespace}` : resolvedSchemaKey;
1771
1932
  if (visited.has(visitKey)) {
1772
1933
  continue;
1773
1934
  }
1774
- const externalXsdText = externalDocuments[ref.schemaLocation];
1935
+ const externalXsdText = resolvedEntry?.text || null;
1775
1936
  if (!externalXsdText) {
1776
1937
  issues.push(
1777
1938
  createIssue({
@@ -1814,9 +1975,6 @@ var UssXsdEngine = (() => {
1814
1975
  ...shouldApplyChameleonInclude ? { _overrideTargetNamespace: schema.targetNamespace } : {}
1815
1976
  });
1816
1977
  if (externalBuild.schema) {
1817
- if (ref.kind === "import") {
1818
- schema.importedSchemas.push(externalBuild.schema);
1819
- }
1820
1978
  if (ref.kind === "include") {
1821
1979
  if (!isIncludeNamespaceCompatible(schema, externalBuild.schema)) {
1822
1980
  issues.push(
@@ -1831,6 +1989,8 @@ var UssXsdEngine = (() => {
1831
1989
  nodeKind: "include",
1832
1990
  details: {
1833
1991
  schemaLocation: ref.schemaLocation,
1992
+ resolvedSchemaKey,
1993
+ resolutionKind: resolution.kind,
1834
1994
  hostTargetNamespace: schema.targetNamespace || null,
1835
1995
  includedTargetNamespace: externalBuild.schema.targetNamespace || null,
1836
1996
  includedDeclaredTargetNamespace: externalDeclaredTargetNamespace,
@@ -1860,6 +2020,8 @@ var UssXsdEngine = (() => {
1860
2020
  nodeKind: "import",
1861
2021
  details: {
1862
2022
  schemaLocation: ref.schemaLocation,
2023
+ resolvedSchemaKey,
2024
+ resolutionKind: resolution.kind,
1863
2025
  declaredNamespace: ref.namespace || null,
1864
2026
  importedTargetNamespace: externalBuild.schema.targetNamespace || null
1865
2027
  }
@@ -2198,12 +2360,72 @@ var UssXsdEngine = (() => {
2198
2360
  }
2199
2361
 
2200
2362
  // src/diagnostics/schemaImportDiagnostics.js
2363
+ function normalizeSchemaPath2(value) {
2364
+ if (!value || typeof value !== "string") return null;
2365
+ const trimmed = value.trim();
2366
+ if (!trimmed) return null;
2367
+ return trimmed.replace(/\\/g, "/").replace(/\/+/g, "/");
2368
+ }
2369
+ function getSchemaPathBasename2(value) {
2370
+ const normalized = normalizeSchemaPath2(value);
2371
+ if (!normalized) return null;
2372
+ const parts = normalized.split("/");
2373
+ return parts[parts.length - 1] || null;
2374
+ }
2375
+ function getExternalDocumentEntries2(externalDocuments) {
2376
+ return Object.entries(externalDocuments || {}).map(([key, text]) => ({
2377
+ key,
2378
+ normalizedKey: normalizeSchemaPath2(key),
2379
+ basename: getSchemaPathBasename2(key),
2380
+ text
2381
+ }));
2382
+ }
2383
+ function getDeclaredTargetNamespaceFromText2(xsdText) {
2384
+ if (typeof xsdText !== "string" || !xsdText.trim()) {
2385
+ return null;
2386
+ }
2387
+ try {
2388
+ const parser = new DOMParser();
2389
+ const doc = parser.parseFromString(xsdText, "application/xml");
2390
+ const parserError = doc.querySelector("parsererror");
2391
+ if (parserError) return null;
2392
+ const root = doc?.documentElement || null;
2393
+ if (!root || root.localName !== "schema") return null;
2394
+ return root.hasAttribute("targetNamespace") ? root.getAttribute("targetNamespace") : null;
2395
+ } catch {
2396
+ return null;
2397
+ }
2398
+ }
2399
+ function hasMatchingExternalDocument(ref, externalDocuments) {
2400
+ const entries = getExternalDocumentEntries2(externalDocuments);
2401
+ const requestedLocation = ref?.schemaLocation || null;
2402
+ const normalizedRequestedLocation = normalizeSchemaPath2(requestedLocation);
2403
+ const requestedBasename = getSchemaPathBasename2(requestedLocation);
2404
+ if (requestedLocation && Object.prototype.hasOwnProperty.call(externalDocuments, requestedLocation)) {
2405
+ return true;
2406
+ }
2407
+ if (normalizedRequestedLocation && entries.some((entry) => entry.normalizedKey === normalizedRequestedLocation)) {
2408
+ return true;
2409
+ }
2410
+ if (requestedBasename && entries.some((entry) => entry.basename === requestedBasename)) {
2411
+ return true;
2412
+ }
2413
+ if (ref?.kind === "import" && ref.namespace) {
2414
+ return entries.some((entry) => {
2415
+ const declaredTargetNamespace = getDeclaredTargetNamespaceFromText2(
2416
+ entry.text
2417
+ );
2418
+ return (declaredTargetNamespace || null) === (ref.namespace || null);
2419
+ });
2420
+ }
2421
+ return false;
2422
+ }
2201
2423
  function runImportDiagnostics(schema, options = {}) {
2202
2424
  const issues = [];
2203
2425
  const externalDocuments = options.externalDocuments || {};
2204
2426
  for (const ref of schema.externalRefs.includes || []) {
2205
2427
  if (!ref.schemaLocation) continue;
2206
- if (externalDocuments[ref.schemaLocation]) continue;
2428
+ if (hasMatchingExternalDocument(ref, externalDocuments)) continue;
2207
2429
  issues.push(
2208
2430
  createIssue({
2209
2431
  code: ISSUE_CODES.XSD_INCLUDE_NOT_PROVIDED,
@@ -2223,7 +2445,7 @@ var UssXsdEngine = (() => {
2223
2445
  }
2224
2446
  for (const ref of schema.externalRefs.imports || []) {
2225
2447
  if (!ref.schemaLocation) continue;
2226
- if (externalDocuments[ref.schemaLocation]) continue;
2448
+ if (hasMatchingExternalDocument(ref, externalDocuments)) continue;
2227
2449
  issues.push(
2228
2450
  createIssue({
2229
2451
  code: ISSUE_CODES.XSD_IMPORT_NOT_PROVIDED,
@@ -2434,7 +2656,7 @@ var UssXsdEngine = (() => {
2434
2656
  }
2435
2657
 
2436
2658
  // src/version.js
2437
- var ENGINE_VERSION = "v0.1.0-rc.2";
2659
+ var ENGINE_VERSION = "v0.1.1";
2438
2660
 
2439
2661
  // src/utils/result.js
2440
2662
  function summarizeIssues(issues = []) {
@@ -3431,6 +3653,14 @@ var UssXsdEngine = (() => {
3431
3653
  state,
3432
3654
  true
3433
3655
  );
3656
+ if (rootNode) {
3657
+ const finalNsAttrs = buildRootNamespaceAttributes(schema, root, state);
3658
+ rootNode.attributes = {
3659
+ ...finalNsAttrs,
3660
+ ...rootNode.attributes
3661
+ // preserve any existing attrs
3662
+ };
3663
+ }
3434
3664
  return {
3435
3665
  rootElementName: root.name,
3436
3666
  rootNode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uss-xsd-engine",
3
- "version": "0.1.0-rc.2",
3
+ "version": "0.1.1",
4
4
  "description": "Browser-first XSD engine for schema diagnostics, tree extraction, sample XML generation, and XML validation.",
5
5
  "type": "module",
6
6
  "main": "dist/uss-xsd-engine.esm.js",