@abapify/ts-xsd 0.4.0 → 0.4.3

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.
@@ -0,0 +1,1822 @@
1
+ import { DOMParser } from "@xmldom/xmldom";
2
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
4
+
5
+ //#region src/xml/dom-utils.ts
6
+ /**
7
+ * Type guard to check if a Node is an Element
8
+ */
9
+ function isElement(node) {
10
+ return node.nodeType === 1;
11
+ }
12
+ /**
13
+ * Get attribute value, handling namespaced attributes
14
+ * Tries direct attribute first, then searches by local name
15
+ */
16
+ function getAttributeValue(node, name) {
17
+ if (node.hasAttribute(name)) return node.getAttribute(name);
18
+ for (let i = 0; i < node.attributes.length; i++) {
19
+ const attr = node.attributes[i];
20
+ if ((attr.localName || attr.name.split(":").pop()) === name) return attr.value;
21
+ }
22
+ return null;
23
+ }
24
+ /**
25
+ * Get child elements by local name (namespace-agnostic)
26
+ */
27
+ function getChildElements(parent, name) {
28
+ const result = [];
29
+ for (let i = 0; i < parent.childNodes.length; i++) {
30
+ const child = parent.childNodes[i];
31
+ if (isElement(child)) {
32
+ if ((child.localName || child.tagName.split(":").pop()) === name) result.push(child);
33
+ }
34
+ }
35
+ return result;
36
+ }
37
+ /**
38
+ * Get all child elements (any name)
39
+ */
40
+ function getAllChildElements(parent) {
41
+ const result = [];
42
+ for (let i = 0; i < parent.childNodes.length; i++) {
43
+ const child = parent.childNodes[i];
44
+ if (isElement(child)) result.push(child);
45
+ }
46
+ return result;
47
+ }
48
+ /**
49
+ * Get text content of an element (concatenates all text nodes)
50
+ */
51
+ function getTextContent(node) {
52
+ let text = "";
53
+ for (let i = 0; i < node.childNodes.length; i++) {
54
+ const child = node.childNodes[i];
55
+ if (child.nodeType === 3) text += child.textContent || "";
56
+ }
57
+ return text.trim();
58
+ }
59
+ /**
60
+ * Get local name of an element (strips namespace prefix)
61
+ */
62
+ function getLocalName(node) {
63
+ return node.localName || node.tagName.split(":").pop() || node.tagName;
64
+ }
65
+
66
+ //#endregion
67
+ //#region src/xsd/parse.ts
68
+ /**
69
+ * XSD Parser - Parse XSD documents to typed Schema objects
70
+ *
71
+ * This parser understands XSD semantics and produces correctly typed output
72
+ * matching the W3C XMLSchema.xsd specification.
73
+ *
74
+ * No intermediate JSON - direct XSD to typed objects.
75
+ */
76
+ /**
77
+ * Parse an XSD string to a typed Schema object
78
+ */
79
+ function parseXsd(xml) {
80
+ const root = new DOMParser().parseFromString(xml, "text/xml").documentElement;
81
+ if (!root || getLocalName(root) !== "schema") throw new Error("Invalid XSD: root element must be xs:schema");
82
+ return parseSchema(root);
83
+ }
84
+ function parseSchema(el) {
85
+ const schema = {};
86
+ copyXmlns(el, schema);
87
+ copyAttr(el, schema, "id");
88
+ copyAttr(el, schema, "targetNamespace");
89
+ copyAttr(el, schema, "version");
90
+ copyAttr(el, schema, "finalDefault");
91
+ copyAttr(el, schema, "blockDefault");
92
+ copyAttr(el, schema, "attributeFormDefault");
93
+ copyAttr(el, schema, "elementFormDefault");
94
+ copyAttr(el, schema, "defaultAttributes");
95
+ copyAttr(el, schema, "xpathDefaultNamespace");
96
+ copyAttr(el, schema, "xml:lang");
97
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
98
+ case "annotation":
99
+ pushTo(schema, "annotation", parseAnnotation(child));
100
+ break;
101
+ case "include":
102
+ pushTo(schema, "include", parseInclude(child));
103
+ break;
104
+ case "import":
105
+ pushTo(schema, "import", parseImport(child));
106
+ break;
107
+ case "redefine":
108
+ pushTo(schema, "redefine", parseRedefine(child));
109
+ break;
110
+ case "override":
111
+ pushTo(schema, "override", parseOverride(child));
112
+ break;
113
+ case "element":
114
+ pushTo(schema, "element", parseTopLevelElement(child));
115
+ break;
116
+ case "attribute":
117
+ pushTo(schema, "attribute", parseTopLevelAttribute(child));
118
+ break;
119
+ case "simpleType":
120
+ pushTo(schema, "simpleType", parseTopLevelSimpleType(child));
121
+ break;
122
+ case "complexType":
123
+ pushTo(schema, "complexType", parseTopLevelComplexType(child));
124
+ break;
125
+ case "group":
126
+ pushTo(schema, "group", parseNamedGroup(child));
127
+ break;
128
+ case "attributeGroup":
129
+ pushTo(schema, "attributeGroup", parseNamedAttributeGroup(child));
130
+ break;
131
+ case "notation":
132
+ pushTo(schema, "notation", parseNotation(child));
133
+ break;
134
+ case "defaultOpenContent": schema.defaultOpenContent = parseDefaultOpenContent(child);
135
+ }
136
+ return schema;
137
+ }
138
+ function parseAnnotation(el) {
139
+ const result = {};
140
+ copyAttr(el, result, "id");
141
+ for (const child of getAllChildElements(el)) {
142
+ const name = getLocalName(child);
143
+ if (name === "documentation") pushTo(result, "documentation", parseDocumentation(child));
144
+ else if (name === "appinfo") pushTo(result, "appinfo", parseAppinfo(child));
145
+ }
146
+ return result;
147
+ }
148
+ function parseDocumentation(el) {
149
+ const result = {};
150
+ copyAttr(el, result, "source");
151
+ copyAttr(el, result, "xml:lang");
152
+ const text = getTextContent(el);
153
+ if (text) result._text = text;
154
+ return result;
155
+ }
156
+ function parseAppinfo(el) {
157
+ const result = {};
158
+ copyAttr(el, result, "source");
159
+ const text = getTextContent(el);
160
+ if (text) result._text = text;
161
+ return result;
162
+ }
163
+ function parseInclude(el) {
164
+ const result = { schemaLocation: "" };
165
+ copyAttr(el, result, "id");
166
+ copyAttr(el, result, "schemaLocation");
167
+ parseAnnotationChild(el, result);
168
+ return result;
169
+ }
170
+ function parseImport(el) {
171
+ const result = {};
172
+ copyAttr(el, result, "id");
173
+ copyAttr(el, result, "namespace");
174
+ copyAttr(el, result, "schemaLocation");
175
+ parseAnnotationChild(el, result);
176
+ return result;
177
+ }
178
+ function parseRedefine(el) {
179
+ const result = { schemaLocation: "" };
180
+ copyAttr(el, result, "id");
181
+ copyAttr(el, result, "schemaLocation");
182
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
183
+ case "annotation":
184
+ pushTo(result, "annotation", parseAnnotation(child));
185
+ break;
186
+ case "simpleType":
187
+ pushTo(result, "simpleType", parseTopLevelSimpleType(child));
188
+ break;
189
+ case "complexType":
190
+ pushTo(result, "complexType", parseTopLevelComplexType(child));
191
+ break;
192
+ case "group":
193
+ pushTo(result, "group", parseNamedGroup(child));
194
+ break;
195
+ case "attributeGroup": pushTo(result, "attributeGroup", parseNamedAttributeGroup(child));
196
+ }
197
+ return result;
198
+ }
199
+ function parseOverride(el) {
200
+ const result = { schemaLocation: "" };
201
+ copyAttr(el, result, "id");
202
+ copyAttr(el, result, "schemaLocation");
203
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
204
+ case "annotation":
205
+ pushTo(result, "annotation", parseAnnotation(child));
206
+ break;
207
+ case "simpleType":
208
+ pushTo(result, "simpleType", parseTopLevelSimpleType(child));
209
+ break;
210
+ case "complexType":
211
+ pushTo(result, "complexType", parseTopLevelComplexType(child));
212
+ break;
213
+ case "group":
214
+ pushTo(result, "group", parseNamedGroup(child));
215
+ break;
216
+ case "attributeGroup":
217
+ pushTo(result, "attributeGroup", parseNamedAttributeGroup(child));
218
+ break;
219
+ case "element":
220
+ pushTo(result, "element", parseTopLevelElement(child));
221
+ break;
222
+ case "attribute":
223
+ pushTo(result, "attribute", parseTopLevelAttribute(child));
224
+ break;
225
+ case "notation": pushTo(result, "notation", parseNotation(child));
226
+ }
227
+ return result;
228
+ }
229
+ function parseTopLevelElement(el) {
230
+ const result = { name: "" };
231
+ copyAttr(el, result, "id");
232
+ copyAttr(el, result, "name");
233
+ copyAttr(el, result, "type");
234
+ copyAttr(el, result, "substitutionGroup");
235
+ copyAttr(el, result, "default");
236
+ copyAttr(el, result, "fixed");
237
+ copyBoolAttr(el, result, "nillable");
238
+ copyBoolAttr(el, result, "abstract");
239
+ copyAttr(el, result, "final");
240
+ copyAttr(el, result, "block");
241
+ parseAnnotationChild(el, result);
242
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
243
+ case "simpleType":
244
+ result.simpleType = parseLocalSimpleType(child);
245
+ break;
246
+ case "complexType":
247
+ result.complexType = parseLocalComplexType(child);
248
+ break;
249
+ case "unique":
250
+ pushTo(result, "unique", parseUnique(child));
251
+ break;
252
+ case "key":
253
+ pushTo(result, "key", parseKey(child));
254
+ break;
255
+ case "keyref":
256
+ pushTo(result, "keyref", parseKeyref(child));
257
+ break;
258
+ case "alternative": pushTo(result, "alternative", parseAlternative(child));
259
+ }
260
+ return result;
261
+ }
262
+ function parseLocalElement(el) {
263
+ const result = {};
264
+ copyAttr(el, result, "id");
265
+ copyAttr(el, result, "name");
266
+ copyAttr(el, result, "ref");
267
+ copyAttr(el, result, "type");
268
+ copyAttr(el, result, "minOccurs");
269
+ copyAttr(el, result, "maxOccurs");
270
+ copyAttr(el, result, "default");
271
+ copyAttr(el, result, "fixed");
272
+ copyBoolAttr(el, result, "nillable");
273
+ copyAttr(el, result, "block");
274
+ copyAttr(el, result, "form");
275
+ copyAttr(el, result, "targetNamespace");
276
+ parseAnnotationChild(el, result);
277
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
278
+ case "simpleType":
279
+ result.simpleType = parseLocalSimpleType(child);
280
+ break;
281
+ case "complexType":
282
+ result.complexType = parseLocalComplexType(child);
283
+ break;
284
+ case "unique":
285
+ pushTo(result, "unique", parseUnique(child));
286
+ break;
287
+ case "key":
288
+ pushTo(result, "key", parseKey(child));
289
+ break;
290
+ case "keyref":
291
+ pushTo(result, "keyref", parseKeyref(child));
292
+ break;
293
+ case "alternative": pushTo(result, "alternative", parseAlternative(child));
294
+ }
295
+ return result;
296
+ }
297
+ function parseTopLevelAttribute(el) {
298
+ const result = { name: "" };
299
+ copyAttr(el, result, "id");
300
+ copyAttr(el, result, "name");
301
+ copyAttr(el, result, "type");
302
+ copyAttr(el, result, "default");
303
+ copyAttr(el, result, "fixed");
304
+ copyBoolAttr(el, result, "inheritable");
305
+ parseAnnotationChild(el, result);
306
+ for (const child of getAllChildElements(el)) if (getLocalName(child) === "simpleType") result.simpleType = parseLocalSimpleType(child);
307
+ return result;
308
+ }
309
+ function parseLocalAttribute(el) {
310
+ const result = {};
311
+ copyAttr(el, result, "id");
312
+ copyAttr(el, result, "name");
313
+ copyAttr(el, result, "ref");
314
+ copyAttr(el, result, "type");
315
+ copyAttr(el, result, "use");
316
+ copyAttr(el, result, "default");
317
+ copyAttr(el, result, "fixed");
318
+ copyAttr(el, result, "form");
319
+ copyAttr(el, result, "targetNamespace");
320
+ copyBoolAttr(el, result, "inheritable");
321
+ parseAnnotationChild(el, result);
322
+ for (const child of getAllChildElements(el)) if (getLocalName(child) === "simpleType") result.simpleType = parseLocalSimpleType(child);
323
+ return result;
324
+ }
325
+ function parseTopLevelComplexType(el) {
326
+ const result = { name: "" };
327
+ copyAttr(el, result, "id");
328
+ copyAttr(el, result, "name");
329
+ copyBoolAttr(el, result, "mixed");
330
+ copyBoolAttr(el, result, "abstract");
331
+ copyAttr(el, result, "final");
332
+ copyAttr(el, result, "block");
333
+ copyBoolAttr(el, result, "defaultAttributesApply");
334
+ parseAnnotationChild(el, result);
335
+ parseComplexTypeContent(el, result);
336
+ return result;
337
+ }
338
+ function parseLocalComplexType(el) {
339
+ const result = {};
340
+ copyAttr(el, result, "id");
341
+ copyBoolAttr(el, result, "mixed");
342
+ parseAnnotationChild(el, result);
343
+ parseComplexTypeContent(el, result);
344
+ return result;
345
+ }
346
+ function parseComplexTypeContent(el, result) {
347
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
348
+ case "simpleContent":
349
+ result.simpleContent = parseSimpleContent(child);
350
+ break;
351
+ case "complexContent":
352
+ result.complexContent = parseComplexContent(child);
353
+ break;
354
+ case "openContent":
355
+ result.openContent = parseOpenContent(child);
356
+ break;
357
+ case "group":
358
+ result.group = parseGroupRef(child);
359
+ break;
360
+ case "all":
361
+ result.all = parseAll(child);
362
+ break;
363
+ case "choice":
364
+ result.choice = parseExplicitGroup(child);
365
+ break;
366
+ case "sequence":
367
+ result.sequence = parseExplicitGroup(child);
368
+ break;
369
+ case "attribute":
370
+ pushTo(result, "attribute", parseLocalAttribute(child));
371
+ break;
372
+ case "attributeGroup":
373
+ pushTo(result, "attributeGroup", parseAttributeGroupRef(child));
374
+ break;
375
+ case "anyAttribute":
376
+ result.anyAttribute = parseAnyAttribute(child);
377
+ break;
378
+ case "assert": pushTo(result, "assert", parseAssertion(child));
379
+ }
380
+ }
381
+ function parseTopLevelSimpleType(el) {
382
+ const result = { name: "" };
383
+ copyAttr(el, result, "id");
384
+ copyAttr(el, result, "name");
385
+ copyAttr(el, result, "final");
386
+ parseAnnotationChild(el, result);
387
+ parseSimpleTypeContent(el, result);
388
+ return result;
389
+ }
390
+ function parseLocalSimpleType(el) {
391
+ const result = {};
392
+ copyAttr(el, result, "id");
393
+ parseAnnotationChild(el, result);
394
+ parseSimpleTypeContent(el, result);
395
+ return result;
396
+ }
397
+ function parseSimpleTypeContent(el, result) {
398
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
399
+ case "restriction":
400
+ result.restriction = parseSimpleTypeRestriction(child);
401
+ break;
402
+ case "list":
403
+ result.list = parseList(child);
404
+ break;
405
+ case "union": result.union = parseUnion(child);
406
+ }
407
+ }
408
+ function parseSimpleTypeRestriction(el) {
409
+ const result = {};
410
+ copyAttr(el, result, "id");
411
+ copyAttr(el, result, "base");
412
+ parseAnnotationChild(el, result);
413
+ for (const child of getAllChildElements(el)) {
414
+ const name = getLocalName(child);
415
+ switch (name) {
416
+ case "simpleType":
417
+ result.simpleType = parseLocalSimpleType(child);
418
+ break;
419
+ case "minExclusive":
420
+ case "minInclusive":
421
+ case "maxExclusive":
422
+ case "maxInclusive":
423
+ case "totalDigits":
424
+ case "fractionDigits":
425
+ case "length":
426
+ case "minLength":
427
+ case "maxLength":
428
+ case "enumeration":
429
+ case "whiteSpace":
430
+ case "explicitTimezone":
431
+ pushTo(result, name, parseFacet(child));
432
+ break;
433
+ case "pattern":
434
+ pushTo(result, "pattern", parsePattern(child));
435
+ break;
436
+ case "assertion": pushTo(result, "assertion", parseAssertion(child));
437
+ }
438
+ }
439
+ return result;
440
+ }
441
+ function parseList(el) {
442
+ const result = {};
443
+ copyAttr(el, result, "id");
444
+ copyAttr(el, result, "itemType");
445
+ parseAnnotationChild(el, result);
446
+ for (const child of getAllChildElements(el)) if (getLocalName(child) === "simpleType") result.simpleType = parseLocalSimpleType(child);
447
+ return result;
448
+ }
449
+ function parseUnion(el) {
450
+ const result = {};
451
+ copyAttr(el, result, "id");
452
+ copyAttr(el, result, "memberTypes");
453
+ parseAnnotationChild(el, result);
454
+ for (const child of getAllChildElements(el)) if (getLocalName(child) === "simpleType") pushTo(result, "simpleType", parseLocalSimpleType(child));
455
+ return result;
456
+ }
457
+ function parseFacet(el) {
458
+ const result = { value: "" };
459
+ copyAttr(el, result, "id");
460
+ copyAttr(el, result, "value");
461
+ copyBoolAttr(el, result, "fixed");
462
+ parseAnnotationChild(el, result);
463
+ return result;
464
+ }
465
+ function parsePattern(el) {
466
+ const result = { value: "" };
467
+ copyAttr(el, result, "id");
468
+ copyAttr(el, result, "value");
469
+ parseAnnotationChild(el, result);
470
+ return result;
471
+ }
472
+ function parseComplexContent(el) {
473
+ const result = {};
474
+ copyAttr(el, result, "id");
475
+ copyBoolAttr(el, result, "mixed");
476
+ parseAnnotationChild(el, result);
477
+ for (const child of getAllChildElements(el)) {
478
+ const name = getLocalName(child);
479
+ if (name === "restriction") result.restriction = parseComplexContentRestriction(child);
480
+ else if (name === "extension") result.extension = parseComplexContentExtension(child);
481
+ }
482
+ return result;
483
+ }
484
+ function parseSimpleContent(el) {
485
+ const result = {};
486
+ copyAttr(el, result, "id");
487
+ parseAnnotationChild(el, result);
488
+ for (const child of getAllChildElements(el)) {
489
+ const name = getLocalName(child);
490
+ if (name === "restriction") result.restriction = parseSimpleContentRestriction(child);
491
+ else if (name === "extension") result.extension = parseSimpleContentExtension(child);
492
+ }
493
+ return result;
494
+ }
495
+ function parseComplexContentRestriction(el) {
496
+ const result = { base: "" };
497
+ copyAttr(el, result, "id");
498
+ copyAttr(el, result, "base");
499
+ parseAnnotationChild(el, result);
500
+ parseComplexTypeContent(el, result);
501
+ return result;
502
+ }
503
+ function parseComplexContentExtension(el) {
504
+ const result = { base: "" };
505
+ copyAttr(el, result, "id");
506
+ copyAttr(el, result, "base");
507
+ parseAnnotationChild(el, result);
508
+ parseComplexTypeContent(el, result);
509
+ return result;
510
+ }
511
+ function parseSimpleContentRestriction(el) {
512
+ const result = { base: "" };
513
+ copyAttr(el, result, "id");
514
+ copyAttr(el, result, "base");
515
+ parseAnnotationChild(el, result);
516
+ for (const child of getAllChildElements(el)) {
517
+ const name = getLocalName(child);
518
+ switch (name) {
519
+ case "simpleType":
520
+ result.simpleType = parseLocalSimpleType(child);
521
+ break;
522
+ case "minExclusive":
523
+ case "minInclusive":
524
+ case "maxExclusive":
525
+ case "maxInclusive":
526
+ case "totalDigits":
527
+ case "fractionDigits":
528
+ case "length":
529
+ case "minLength":
530
+ case "maxLength":
531
+ case "enumeration":
532
+ case "whiteSpace":
533
+ case "explicitTimezone":
534
+ pushTo(result, name, parseFacet(child));
535
+ break;
536
+ case "pattern":
537
+ pushTo(result, "pattern", parsePattern(child));
538
+ break;
539
+ case "assertion":
540
+ pushTo(result, "assertion", parseAssertion(child));
541
+ break;
542
+ case "attribute":
543
+ pushTo(result, "attribute", parseLocalAttribute(child));
544
+ break;
545
+ case "attributeGroup":
546
+ pushTo(result, "attributeGroup", parseAttributeGroupRef(child));
547
+ break;
548
+ case "anyAttribute":
549
+ result.anyAttribute = parseAnyAttribute(child);
550
+ break;
551
+ case "assert": pushTo(result, "assert", parseAssertion(child));
552
+ }
553
+ }
554
+ return result;
555
+ }
556
+ function parseSimpleContentExtension(el) {
557
+ const result = { base: "" };
558
+ copyAttr(el, result, "id");
559
+ copyAttr(el, result, "base");
560
+ parseAnnotationChild(el, result);
561
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
562
+ case "attribute":
563
+ pushTo(result, "attribute", parseLocalAttribute(child));
564
+ break;
565
+ case "attributeGroup":
566
+ pushTo(result, "attributeGroup", parseAttributeGroupRef(child));
567
+ break;
568
+ case "anyAttribute":
569
+ result.anyAttribute = parseAnyAttribute(child);
570
+ break;
571
+ case "assert": pushTo(result, "assert", parseAssertion(child));
572
+ }
573
+ return result;
574
+ }
575
+ function parseExplicitGroup(el) {
576
+ const result = {};
577
+ copyAttr(el, result, "id");
578
+ copyAttr(el, result, "minOccurs");
579
+ copyAttr(el, result, "maxOccurs");
580
+ parseAnnotationChild(el, result);
581
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
582
+ case "element":
583
+ pushTo(result, "element", parseLocalElement(child));
584
+ break;
585
+ case "group":
586
+ pushTo(result, "group", parseGroupRef(child));
587
+ break;
588
+ case "choice":
589
+ pushTo(result, "choice", parseExplicitGroup(child));
590
+ break;
591
+ case "sequence":
592
+ pushTo(result, "sequence", parseExplicitGroup(child));
593
+ break;
594
+ case "any": pushTo(result, "any", parseAny(child));
595
+ }
596
+ return result;
597
+ }
598
+ function parseAll(el) {
599
+ const result = {};
600
+ copyAttr(el, result, "id");
601
+ copyAttr(el, result, "minOccurs");
602
+ copyAttr(el, result, "maxOccurs");
603
+ parseAnnotationChild(el, result);
604
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
605
+ case "element":
606
+ pushTo(result, "element", parseLocalElement(child));
607
+ break;
608
+ case "any":
609
+ pushTo(result, "any", parseAny(child));
610
+ break;
611
+ case "group": pushTo(result, "group", parseGroupRef(child));
612
+ }
613
+ return result;
614
+ }
615
+ function parseNamedGroup(el) {
616
+ const result = { name: "" };
617
+ copyAttr(el, result, "id");
618
+ copyAttr(el, result, "name");
619
+ parseAnnotationChild(el, result);
620
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
621
+ case "all":
622
+ result.all = parseAll(child);
623
+ break;
624
+ case "choice":
625
+ result.choice = parseExplicitGroup(child);
626
+ break;
627
+ case "sequence": result.sequence = parseExplicitGroup(child);
628
+ }
629
+ return result;
630
+ }
631
+ function parseGroupRef(el) {
632
+ const result = { ref: "" };
633
+ copyAttr(el, result, "id");
634
+ copyAttr(el, result, "ref");
635
+ copyAttr(el, result, "minOccurs");
636
+ copyAttr(el, result, "maxOccurs");
637
+ parseAnnotationChild(el, result);
638
+ return result;
639
+ }
640
+ function parseNamedAttributeGroup(el) {
641
+ const result = { name: "" };
642
+ copyAttr(el, result, "id");
643
+ copyAttr(el, result, "name");
644
+ parseAnnotationChild(el, result);
645
+ for (const child of getAllChildElements(el)) switch (getLocalName(child)) {
646
+ case "attribute":
647
+ pushTo(result, "attribute", parseLocalAttribute(child));
648
+ break;
649
+ case "attributeGroup":
650
+ pushTo(result, "attributeGroup", parseAttributeGroupRef(child));
651
+ break;
652
+ case "anyAttribute": result.anyAttribute = parseAnyAttribute(child);
653
+ }
654
+ return result;
655
+ }
656
+ function parseAttributeGroupRef(el) {
657
+ const result = { ref: "" };
658
+ copyAttr(el, result, "id");
659
+ copyAttr(el, result, "ref");
660
+ parseAnnotationChild(el, result);
661
+ return result;
662
+ }
663
+ function parseAny(el) {
664
+ const result = {};
665
+ copyAttr(el, result, "id");
666
+ copyAttr(el, result, "minOccurs");
667
+ copyAttr(el, result, "maxOccurs");
668
+ copyAttr(el, result, "namespace");
669
+ copyAttr(el, result, "processContents");
670
+ copyAttr(el, result, "notNamespace");
671
+ copyAttr(el, result, "notQName");
672
+ parseAnnotationChild(el, result);
673
+ return result;
674
+ }
675
+ function parseAnyAttribute(el) {
676
+ const result = {};
677
+ copyAttr(el, result, "id");
678
+ copyAttr(el, result, "namespace");
679
+ copyAttr(el, result, "processContents");
680
+ copyAttr(el, result, "notNamespace");
681
+ copyAttr(el, result, "notQName");
682
+ parseAnnotationChild(el, result);
683
+ return result;
684
+ }
685
+ function parseUnique(el) {
686
+ const result = { name: "" };
687
+ copyAttr(el, result, "id");
688
+ copyAttr(el, result, "name");
689
+ copyAttr(el, result, "ref");
690
+ parseAnnotationChild(el, result);
691
+ for (const child of getAllChildElements(el)) {
692
+ const name = getLocalName(child);
693
+ if (name === "selector") result.selector = parseSelector(child);
694
+ else if (name === "field") pushTo(result, "field", parseField(child));
695
+ }
696
+ return result;
697
+ }
698
+ function parseKey(el) {
699
+ const result = { name: "" };
700
+ copyAttr(el, result, "id");
701
+ copyAttr(el, result, "name");
702
+ copyAttr(el, result, "ref");
703
+ parseAnnotationChild(el, result);
704
+ for (const child of getAllChildElements(el)) {
705
+ const name = getLocalName(child);
706
+ if (name === "selector") result.selector = parseSelector(child);
707
+ else if (name === "field") pushTo(result, "field", parseField(child));
708
+ }
709
+ return result;
710
+ }
711
+ function parseKeyref(el) {
712
+ const result = {
713
+ name: "",
714
+ refer: ""
715
+ };
716
+ copyAttr(el, result, "id");
717
+ copyAttr(el, result, "name");
718
+ copyAttr(el, result, "ref");
719
+ copyAttr(el, result, "refer");
720
+ parseAnnotationChild(el, result);
721
+ for (const child of getAllChildElements(el)) {
722
+ const name = getLocalName(child);
723
+ if (name === "selector") result.selector = parseSelector(child);
724
+ else if (name === "field") pushTo(result, "field", parseField(child));
725
+ }
726
+ return result;
727
+ }
728
+ function parseSelector(el) {
729
+ const result = { xpath: "" };
730
+ copyAttr(el, result, "id");
731
+ copyAttr(el, result, "xpath");
732
+ copyAttr(el, result, "xpathDefaultNamespace");
733
+ parseAnnotationChild(el, result);
734
+ return result;
735
+ }
736
+ function parseField(el) {
737
+ const result = { xpath: "" };
738
+ copyAttr(el, result, "id");
739
+ copyAttr(el, result, "xpath");
740
+ copyAttr(el, result, "xpathDefaultNamespace");
741
+ parseAnnotationChild(el, result);
742
+ return result;
743
+ }
744
+ function parseOpenContent(el) {
745
+ const result = {};
746
+ copyAttr(el, result, "id");
747
+ copyAttr(el, result, "mode");
748
+ parseAnnotationChild(el, result);
749
+ for (const child of getAllChildElements(el)) if (getLocalName(child) === "any") result.any = parseAny(child);
750
+ return result;
751
+ }
752
+ function parseDefaultOpenContent(el) {
753
+ const result = { any: {} };
754
+ copyAttr(el, result, "id");
755
+ copyBoolAttr(el, result, "appliesToEmpty");
756
+ copyAttr(el, result, "mode");
757
+ parseAnnotationChild(el, result);
758
+ for (const child of getAllChildElements(el)) if (getLocalName(child) === "any") result.any = parseAny(child);
759
+ return result;
760
+ }
761
+ function parseAssertion(el) {
762
+ const result = {};
763
+ copyAttr(el, result, "id");
764
+ copyAttr(el, result, "test");
765
+ copyAttr(el, result, "xpathDefaultNamespace");
766
+ parseAnnotationChild(el, result);
767
+ return result;
768
+ }
769
+ function parseAlternative(el) {
770
+ const result = {};
771
+ copyAttr(el, result, "id");
772
+ copyAttr(el, result, "test");
773
+ copyAttr(el, result, "type");
774
+ copyAttr(el, result, "xpathDefaultNamespace");
775
+ parseAnnotationChild(el, result);
776
+ for (const child of getAllChildElements(el)) {
777
+ const name = getLocalName(child);
778
+ if (name === "simpleType") result.simpleType = parseLocalSimpleType(child);
779
+ else if (name === "complexType") result.complexType = parseLocalComplexType(child);
780
+ }
781
+ return result;
782
+ }
783
+ function parseNotation(el) {
784
+ const result = {
785
+ name: "",
786
+ public: ""
787
+ };
788
+ copyAttr(el, result, "id");
789
+ copyAttr(el, result, "name");
790
+ copyAttr(el, result, "public");
791
+ copyAttr(el, result, "system");
792
+ parseAnnotationChild(el, result);
793
+ return result;
794
+ }
795
+ function copyAttr(el, target, name) {
796
+ if (el.hasAttribute(name)) {
797
+ const value = el.getAttribute(name);
798
+ if (value !== null) target[name] = value;
799
+ }
800
+ }
801
+ function copyBoolAttr(el, target, name) {
802
+ if (el.hasAttribute(name)) {
803
+ const value = el.getAttribute(name);
804
+ if (value !== null) target[name] = value === "true";
805
+ }
806
+ }
807
+ function pushTo(target, name, value) {
808
+ if (!target[name]) target[name] = [];
809
+ target[name].push(value);
810
+ }
811
+ function parseAnnotationChild(el, result) {
812
+ for (const child of getAllChildElements(el)) if (getLocalName(child) === "annotation") {
813
+ result.annotation = parseAnnotation(child);
814
+ break;
815
+ }
816
+ }
817
+ /**
818
+ * Extract xmlns declarations from an element's attributes.
819
+ * Returns undefined if no xmlns declarations found.
820
+ *
821
+ * @example
822
+ * For <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://example.com">
823
+ * Returns: { xs: "http://www.w3.org/2001/XMLSchema", tns: "http://example.com" }
824
+ *
825
+ * For <xs:element xmlns="http://default.com">
826
+ * Returns: { "": "http://default.com" }
827
+ */
828
+ function extractXmlns(el) {
829
+ const xmlns = {};
830
+ let hasXmlns = false;
831
+ for (let i = 0; i < el.attributes.length; i++) {
832
+ const attr = el.attributes[i];
833
+ const name = attr.name;
834
+ const value = attr.value;
835
+ if (name === "xmlns") {
836
+ xmlns[""] = value;
837
+ hasXmlns = true;
838
+ } else if (name.startsWith("xmlns:")) {
839
+ const prefix = name.substring(6);
840
+ xmlns[prefix] = value;
841
+ hasXmlns = true;
842
+ }
843
+ }
844
+ return hasXmlns ? xmlns : void 0;
845
+ }
846
+ /**
847
+ * Copy xmlns declarations to target if present
848
+ */
849
+ function copyXmlns(el, target) {
850
+ const xmlns = extractXmlns(el);
851
+ if (xmlns) target.$xmlns = xmlns;
852
+ }
853
+
854
+ //#endregion
855
+ //#region src/xsd/traverser.ts
856
+ /**
857
+ * Base class for OO schema traversal using real W3C XSD types.
858
+ *
859
+ * Subclass and override the `on*` methods you need.
860
+ * Context is available via `this` - no parameter passing needed.
861
+ */
862
+ var SchemaTraverser = class {
863
+ /** Root schema being traversed */
864
+ rootSchema;
865
+ /** Current schema being visited */
866
+ currentSchema;
867
+ /** Source of current node (direct, redefine, override, include, import) */
868
+ source = "direct";
869
+ /** Depth in schema hierarchy (0 = root) */
870
+ depth = 0;
871
+ /** Traversal options */
872
+ options = {
873
+ includeImports: true,
874
+ includeIncludes: true,
875
+ maxDepth: Infinity
876
+ };
877
+ /** Visited schemas (prevents infinite loops) */
878
+ visited = /* @__PURE__ */ new Set();
879
+ /**
880
+ * Traverse a schema and all its imports/includes.
881
+ * Override `on*` methods to handle specific node types.
882
+ */
883
+ traverse(schema, options = {}) {
884
+ this.rootSchema = schema;
885
+ this.options = {
886
+ ...this.options,
887
+ ...options
888
+ };
889
+ this.visited.clear();
890
+ this.traverseSchema(schema, "direct", 0);
891
+ return this;
892
+ }
893
+ /** Called when entering a schema */
894
+ onEnterSchema(_schema) {}
895
+ /** Called when leaving a schema */
896
+ onLeaveSchema(_schema) {}
897
+ /** Called for each top-level complexType */
898
+ onComplexType(_ct) {}
899
+ /** Called for each top-level simpleType */
900
+ onSimpleType(_st) {}
901
+ /** Called for each top-level element */
902
+ onElement(_element) {}
903
+ /** Called for each top-level attribute */
904
+ onAttribute(_attr) {}
905
+ /** Called for each named group */
906
+ onGroup(_group) {}
907
+ /** Called for each named attributeGroup */
908
+ onAttributeGroup(_group) {}
909
+ /** Called for each redefine block */
910
+ onRedefine(_redefine) {}
911
+ /** Called for each override block */
912
+ onOverride(_override) {}
913
+ traverseSchema(schema, source, depth) {
914
+ if (this.visited.has(schema)) return;
915
+ if (depth > this.options.maxDepth) return;
916
+ this.visited.add(schema);
917
+ this.currentSchema = schema;
918
+ this.source = source;
919
+ this.depth = depth;
920
+ this.onEnterSchema(schema);
921
+ this.traverseSchemaChildren(schema);
922
+ this.traverseRedefines(schema);
923
+ this.traverseOverrides(schema);
924
+ this.traverseIncludes(schema, depth);
925
+ this.traverseImports(schema, depth);
926
+ this.onLeaveSchema(schema);
927
+ }
928
+ traverseSchemaChildren(schema) {
929
+ if (schema.complexType) for (const ct of schema.complexType) this.onComplexType(ct);
930
+ if (schema.simpleType) for (const st of schema.simpleType) this.onSimpleType(st);
931
+ if (schema.element) for (const element of schema.element) this.onElement(element);
932
+ if (schema.attribute) for (const attr of schema.attribute) this.onAttribute(attr);
933
+ if (schema.group) for (const group of schema.group) this.onGroup(group);
934
+ if (schema.attributeGroup) for (const group of schema.attributeGroup) this.onAttributeGroup(group);
935
+ }
936
+ traverseRedefines(schema) {
937
+ if (!schema.redefine) return;
938
+ const prevSource = this.source;
939
+ this.source = "redefine";
940
+ for (const redefine of schema.redefine) {
941
+ this.onRedefine(redefine);
942
+ if (redefine.complexType) for (const ct of redefine.complexType) this.onComplexType(ct);
943
+ if (redefine.simpleType) for (const st of redefine.simpleType) this.onSimpleType(st);
944
+ if (redefine.group) for (const group of redefine.group) this.onGroup(group);
945
+ if (redefine.attributeGroup) for (const group of redefine.attributeGroup) this.onAttributeGroup(group);
946
+ }
947
+ this.source = prevSource;
948
+ }
949
+ traverseOverrides(schema) {
950
+ if (!schema.override) return;
951
+ const prevSource = this.source;
952
+ this.source = "override";
953
+ for (const override of schema.override) {
954
+ this.onOverride(override);
955
+ if (override.complexType) for (const ct of override.complexType) this.onComplexType(ct);
956
+ if (override.simpleType) for (const st of override.simpleType) this.onSimpleType(st);
957
+ if (override.element) for (const element of override.element) this.onElement(element);
958
+ if (override.attribute) for (const attr of override.attribute) this.onAttribute(attr);
959
+ if (override.group) for (const group of override.group) this.onGroup(group);
960
+ if (override.attributeGroup) for (const group of override.attributeGroup) this.onAttributeGroup(group);
961
+ }
962
+ this.source = prevSource;
963
+ }
964
+ traverseIncludes(schema, depth) {
965
+ if (!this.options.includeIncludes || !schema.$includes) return;
966
+ for (const included of schema.$includes) this.traverseSchema(included, "include", depth + 1);
967
+ }
968
+ traverseImports(schema, depth) {
969
+ if (!this.options.includeImports || !schema.$imports) return;
970
+ for (const imported of schema.$imports) this.traverseSchema(imported, "import", depth + 1);
971
+ }
972
+ };
973
+ /**
974
+ * Resolves a schema hierarchy into a flat structure.
975
+ * All types are collected into Maps for O(1) lookup.
976
+ *
977
+ * Precedence rules:
978
+ * - redefine/override types take precedence over original
979
+ * - root schema types take precedence over imported/included
980
+ */
981
+ var SchemaResolver = class extends SchemaTraverser {
982
+ complexTypes = /* @__PURE__ */ new Map();
983
+ simpleTypes = /* @__PURE__ */ new Map();
984
+ elements = /* @__PURE__ */ new Map();
985
+ attributes = /* @__PURE__ */ new Map();
986
+ groups = /* @__PURE__ */ new Map();
987
+ attributeGroups = /* @__PURE__ */ new Map();
988
+ xmlns = /* @__PURE__ */ new Map();
989
+ substitutionGroups = /* @__PURE__ */ new Map();
990
+ /** Get the resolved schema structure */
991
+ getResolved() {
992
+ return {
993
+ complexTypes: this.complexTypes,
994
+ simpleTypes: this.simpleTypes,
995
+ elements: this.elements,
996
+ attributes: this.attributes,
997
+ groups: this.groups,
998
+ attributeGroups: this.attributeGroups,
999
+ xmlns: this.xmlns,
1000
+ substitutionGroups: this.substitutionGroups
1001
+ };
1002
+ }
1003
+ onEnterSchema(schema) {
1004
+ if (schema.$xmlns) {
1005
+ for (const [prefix, uri] of Object.entries(schema.$xmlns)) if (!this.xmlns.has(prefix)) this.xmlns.set(prefix, uri);
1006
+ }
1007
+ }
1008
+ onComplexType(ct) {
1009
+ if (!this.complexTypes.has(ct.name) || this.source === "redefine" || this.source === "override" || this.depth === 0 && this.source === "direct") this.complexTypes.set(ct.name, {
1010
+ ct,
1011
+ schema: this.currentSchema
1012
+ });
1013
+ }
1014
+ onSimpleType(st) {
1015
+ if (!this.simpleTypes.has(st.name) || this.source === "redefine" || this.source === "override" || this.depth === 0 && this.source === "direct") this.simpleTypes.set(st.name, {
1016
+ st,
1017
+ schema: this.currentSchema
1018
+ });
1019
+ }
1020
+ onElement(element) {
1021
+ if (!this.elements.has(element.name) || this.source === "override" || this.depth === 0 && this.source === "direct") this.elements.set(element.name, {
1022
+ element,
1023
+ schema: this.currentSchema
1024
+ });
1025
+ if (element.substitutionGroup) {
1026
+ const abstractName = stripNsPrefix(element.substitutionGroup);
1027
+ const existing = this.substitutionGroups.get(abstractName) ?? [];
1028
+ existing.push(element);
1029
+ this.substitutionGroups.set(abstractName, existing);
1030
+ }
1031
+ }
1032
+ onAttribute(attr) {
1033
+ if (!this.attributes.has(attr.name) || this.source === "override" || this.depth === 0 && this.source === "direct") this.attributes.set(attr.name, {
1034
+ attr,
1035
+ schema: this.currentSchema
1036
+ });
1037
+ }
1038
+ onGroup(group) {
1039
+ if (!this.groups.has(group.name) || this.source === "redefine" || this.source === "override" || this.depth === 0 && this.source === "direct") this.groups.set(group.name, {
1040
+ group,
1041
+ schema: this.currentSchema
1042
+ });
1043
+ }
1044
+ onAttributeGroup(group) {
1045
+ if (!this.attributeGroups.has(group.name) || this.source === "redefine" || this.source === "override" || this.depth === 0 && this.source === "direct") this.attributeGroups.set(group.name, {
1046
+ group,
1047
+ schema: this.currentSchema
1048
+ });
1049
+ }
1050
+ };
1051
+ /**
1052
+ * Strip namespace prefix from a QName (e.g., "xs:string" -> "string")
1053
+ */
1054
+ function stripNsPrefix(qname) {
1055
+ const colonIndex = qname.indexOf(":");
1056
+ return colonIndex >= 0 ? qname.slice(colonIndex + 1) : qname;
1057
+ }
1058
+ /**
1059
+ * Resolve a schema hierarchy into a flat structure.
1060
+ * Convenience function that creates a SchemaResolver and returns the result.
1061
+ */
1062
+ function resolveSchemaTypes(schema, options = {}) {
1063
+ const resolver = new SchemaResolver();
1064
+ resolver.traverse(schema, options);
1065
+ return resolver.getResolved();
1066
+ }
1067
+
1068
+ //#endregion
1069
+ //#region src/xsd/resolve.ts
1070
+ /**
1071
+ * Collects all schema components into Maps for resolution.
1072
+ *
1073
+ * IMPORTANT: Elements are only collected from schemas with the SAME targetNamespace
1074
+ * as the root schema. This follows XSD semantics where xs:import brings in types
1075
+ * from a different namespace but doesn't merge elements into the current namespace.
1076
+ */
1077
+ var SchemaCollector = class extends SchemaTraverser {
1078
+ complexTypes = /* @__PURE__ */ new Map();
1079
+ simpleTypes = /* @__PURE__ */ new Map();
1080
+ elements = /* @__PURE__ */ new Map();
1081
+ groups = /* @__PURE__ */ new Map();
1082
+ attributeGroups = /* @__PURE__ */ new Map();
1083
+ substitutionGroups = /* @__PURE__ */ new Map();
1084
+ xmlns = /* @__PURE__ */ new Map();
1085
+ onEnterSchema(schema) {
1086
+ if (schema.$xmlns) {
1087
+ for (const [prefix, uri] of Object.entries(schema.$xmlns)) if (!this.xmlns.has(prefix)) this.xmlns.set(prefix, uri);
1088
+ }
1089
+ }
1090
+ onComplexType(ct) {
1091
+ if (!this.complexTypes.has(ct.name)) this.complexTypes.set(ct.name, ct);
1092
+ }
1093
+ onSimpleType(st) {
1094
+ if (!this.simpleTypes.has(st.name)) this.simpleTypes.set(st.name, st);
1095
+ }
1096
+ onElement(element) {
1097
+ const rootNs = this.rootSchema.targetNamespace;
1098
+ const currentNs = this.currentSchema.targetNamespace;
1099
+ const sameOrNoNamespace = currentNs === rootNs || !currentNs;
1100
+ const hasSubstitutionGroup = !!element.substitutionGroup;
1101
+ const isAbstract = !!element.abstract;
1102
+ if ((sameOrNoNamespace || hasSubstitutionGroup || isAbstract) && !this.elements.has(element.name)) this.elements.set(element.name, element);
1103
+ if (element.substitutionGroup) {
1104
+ const abstractName = stripNsPrefix(element.substitutionGroup);
1105
+ const existing = this.substitutionGroups.get(abstractName) ?? [];
1106
+ existing.push(element);
1107
+ this.substitutionGroups.set(abstractName, existing);
1108
+ }
1109
+ }
1110
+ onGroup(group) {
1111
+ if (!this.groups.has(group.name)) this.groups.set(group.name, group);
1112
+ }
1113
+ onAttributeGroup(group) {
1114
+ if (!this.attributeGroups.has(group.name)) this.attributeGroups.set(group.name, group);
1115
+ }
1116
+ };
1117
+ /**
1118
+ * Resolve a schema by merging all imports/includes and expanding all references.
1119
+ * Returns a new self-contained schema with no external dependencies.
1120
+ */
1121
+ function resolveSchema(schema, options = {}) {
1122
+ const { resolveImports = true, resolveIncludes = true, expandExtensions = true, expandSubstitutions = true, filterToRootElements = false, keepImportsRef = false } = options;
1123
+ const collector = new SchemaCollector();
1124
+ collector.traverse(schema, {
1125
+ includeImports: resolveImports,
1126
+ includeIncludes: resolveIncludes
1127
+ });
1128
+ let elements;
1129
+ if (filterToRootElements) {
1130
+ const referencedElements = /* @__PURE__ */ new Set();
1131
+ for (const el of collector.elements.values()) collectElementRefs(el, referencedElements);
1132
+ for (const ct of collector.complexTypes.values()) collectElementRefsFromType(ct, referencedElements);
1133
+ elements = Array.from(collector.elements.values()).filter((el) => {
1134
+ if (el.abstract === true) return false;
1135
+ if (referencedElements.has(el.name)) return false;
1136
+ return true;
1137
+ });
1138
+ } else elements = Array.from(collector.elements.values());
1139
+ let resolvedComplexTypes = Array.from(collector.complexTypes.values());
1140
+ if (expandExtensions) resolvedComplexTypes = resolvedComplexTypes.map((ct) => expandComplexTypeExtension(ct, collector.complexTypes));
1141
+ if (expandSubstitutions) resolvedComplexTypes = resolvedComplexTypes.map((ct) => expandSubstitutionGroupsInType(ct, collector.elements, collector.substitutionGroups));
1142
+ const resolved = {
1143
+ targetNamespace: schema.targetNamespace,
1144
+ elementFormDefault: schema.elementFormDefault,
1145
+ $filename: schema.$filename,
1146
+ $xmlns: collector.xmlns.size > 0 ? Object.fromEntries(collector.xmlns) : schema.$xmlns
1147
+ };
1148
+ if (elements.length > 0) resolved.element = elements;
1149
+ if (resolvedComplexTypes.length > 0) resolved.complexType = resolvedComplexTypes;
1150
+ if (collector.simpleTypes.size > 0) resolved.simpleType = Array.from(collector.simpleTypes.values());
1151
+ if (collector.groups.size > 0) resolved.group = Array.from(collector.groups.values());
1152
+ if (collector.attributeGroups.size > 0) resolved.attributeGroup = Array.from(collector.attributeGroups.values());
1153
+ if (keepImportsRef && schema.$imports) resolved.$imports = schema.$imports;
1154
+ return resolved;
1155
+ }
1156
+ /**
1157
+ * Expand complexContent/extension by merging base type properties.
1158
+ * Uses a visited set to prevent infinite recursion on circular inheritance.
1159
+ */
1160
+ function expandComplexTypeExtension(ct, allTypes, visited = /* @__PURE__ */ new Set()) {
1161
+ const extension = ct.complexContent?.extension;
1162
+ if (!extension?.base) return ct;
1163
+ if (visited.has(ct.name)) return ct;
1164
+ visited.add(ct.name);
1165
+ const mergedElements = [];
1166
+ const mergedAttributes = [];
1167
+ const baseName = stripNsPrefix(extension.base);
1168
+ const baseType = allTypes.get(baseName);
1169
+ if (baseType && !visited.has(baseName)) {
1170
+ const expandedBase = expandComplexTypeExtension(baseType, allTypes, visited);
1171
+ collectElementsFromType(expandedBase, mergedElements);
1172
+ if (expandedBase.attribute) mergedAttributes.push(...expandedBase.attribute);
1173
+ }
1174
+ collectElementsFromGroup(extension.sequence, mergedElements);
1175
+ collectElementsFromGroup(extension.choice, mergedElements);
1176
+ collectElementsFromGroup(extension.all, mergedElements);
1177
+ if (extension.attribute) mergedAttributes.push(...extension.attribute);
1178
+ const flattened = { name: ct.name };
1179
+ if (mergedElements.length > 0) flattened.all = { element: mergedElements };
1180
+ if (mergedAttributes.length > 0) flattened.attribute = mergedAttributes;
1181
+ for (const [key, value] of Object.entries(ct)) if (![
1182
+ "name",
1183
+ "complexContent",
1184
+ "all",
1185
+ "sequence",
1186
+ "choice",
1187
+ "attribute"
1188
+ ].includes(key)) flattened[key] = value;
1189
+ return flattened;
1190
+ }
1191
+ /**
1192
+ * Collect elements from a complex type's content model.
1193
+ */
1194
+ function collectElementsFromType(ct, elements) {
1195
+ collectElementsFromGroup(ct.sequence, elements);
1196
+ collectElementsFromGroup(ct.choice, elements);
1197
+ collectElementsFromGroup(ct.all, elements);
1198
+ }
1199
+ /**
1200
+ * Collect elements from a group (sequence/choice/all).
1201
+ */
1202
+ function collectElementsFromGroup(group, elements) {
1203
+ if (!group?.element) return;
1204
+ elements.push(...group.element);
1205
+ }
1206
+ /**
1207
+ * Expand substitution group references in a complex type.
1208
+ * Replaces abstract element refs with concrete substitute elements.
1209
+ */
1210
+ function expandSubstitutionGroupsInType(ct, allElements, substitutionGroups) {
1211
+ let changed = false;
1212
+ const result = { ...ct };
1213
+ if (ct.sequence) {
1214
+ const expanded = expandSubstitutionGroupsInGroup(ct.sequence, allElements, substitutionGroups);
1215
+ if (expanded !== ct.sequence) {
1216
+ result.sequence = expanded;
1217
+ changed = true;
1218
+ }
1219
+ }
1220
+ if (ct.all) {
1221
+ const expanded = expandSubstitutionGroupsInGroup(ct.all, allElements, substitutionGroups);
1222
+ if (expanded !== ct.all) {
1223
+ result.all = expanded;
1224
+ changed = true;
1225
+ }
1226
+ }
1227
+ if (ct.choice) {
1228
+ const expanded = expandSubstitutionGroupsInGroup(ct.choice, allElements, substitutionGroups);
1229
+ if (expanded !== ct.choice) {
1230
+ result.choice = expanded;
1231
+ changed = true;
1232
+ }
1233
+ }
1234
+ return changed ? result : ct;
1235
+ }
1236
+ /**
1237
+ * Expand substitution groups in a group (sequence/all/choice).
1238
+ */
1239
+ function expandSubstitutionGroupsInGroup(group, allElements, substitutionGroups) {
1240
+ if (!group.element) return group;
1241
+ const expandedElements = [];
1242
+ let hasChanges = false;
1243
+ for (const el of group.element) {
1244
+ if (el.ref) {
1245
+ const refName = stripNsPrefix(el.ref);
1246
+ if (allElements.get(refName)?.abstract) {
1247
+ const substitutes = substitutionGroups.get(refName);
1248
+ if (substitutes && substitutes.length > 0) {
1249
+ for (const sub of substitutes) expandedElements.push({
1250
+ name: sub.name,
1251
+ type: sub.type,
1252
+ minOccurs: el.minOccurs ?? 0,
1253
+ maxOccurs: el.maxOccurs
1254
+ });
1255
+ hasChanges = true;
1256
+ continue;
1257
+ }
1258
+ }
1259
+ }
1260
+ expandedElements.push(el);
1261
+ }
1262
+ if (!hasChanges) return group;
1263
+ return {
1264
+ ...group,
1265
+ element: expandedElements
1266
+ };
1267
+ }
1268
+ /**
1269
+ * Get all substitutes for an abstract element.
1270
+ */
1271
+ function getSubstitutes(abstractElementName, schema) {
1272
+ const collector = new SchemaCollector();
1273
+ collector.traverse(schema);
1274
+ return collector.substitutionGroups.get(abstractElementName) ?? [];
1275
+ }
1276
+ /**
1277
+ * Collect element refs from an element's nested structure
1278
+ */
1279
+ function collectElementRefs(el, refs) {
1280
+ const record = el;
1281
+ if (record.complexType) collectElementRefsFromType(record.complexType, refs);
1282
+ }
1283
+ /**
1284
+ * Recursively collect element refs from a complex type
1285
+ */
1286
+ function collectElementRefsFromType(ct, refs) {
1287
+ const record = ct;
1288
+ for (const groupKey of [
1289
+ "sequence",
1290
+ "all",
1291
+ "choice"
1292
+ ]) {
1293
+ const group = record[groupKey];
1294
+ if (group?.element) {
1295
+ const elements = group.element;
1296
+ for (const el of elements) {
1297
+ if (el.ref) {
1298
+ const refName = stripNsPrefix(el.ref);
1299
+ refs.add(refName);
1300
+ }
1301
+ if (el.complexType) collectElementRefsFromType(el.complexType, refs);
1302
+ }
1303
+ }
1304
+ }
1305
+ if (record.complexContent) {
1306
+ const cc = record.complexContent;
1307
+ if (cc.extension) collectElementRefsFromType(cc.extension, refs);
1308
+ }
1309
+ }
1310
+
1311
+ //#endregion
1312
+ //#region src/xsd/loader.ts
1313
+ /**
1314
+ * Schema Loader - Load and parse XSD files from disk
1315
+ *
1316
+ * Simple loader that reads XSD files and parses them into Schema objects.
1317
+ * Resolution of imports/includes is handled by the resolver.
1318
+ */
1319
+ /**
1320
+ * Default XSD loader - reads from filesystem
1321
+ */
1322
+ function defaultLoader(schemaLocation, basePath) {
1323
+ const fullPath = resolve(basePath, schemaLocation);
1324
+ if (!existsSync(fullPath)) return null;
1325
+ return readFileSync(fullPath, "utf-8");
1326
+ }
1327
+ /**
1328
+ * Load and parse a single XSD file.
1329
+ *
1330
+ * @param schemaPath - Path to the XSD file
1331
+ * @param options - Loader options
1332
+ * @param options.autoLink - Populate $imports/$includes with loaded schemas (preserves structure)
1333
+ * @param options.autoResolve - Flatten into single schema with all types merged (implies autoLink)
1334
+ * @returns Parsed schema
1335
+ *
1336
+ * @example
1337
+ * ```typescript
1338
+ * // Just parse - no linking
1339
+ * const schema = loadSchema('/path/to/schema.xsd');
1340
+ *
1341
+ * // Link - populate $imports/$includes (preserves multi-schema structure)
1342
+ * const linked = loadSchema('/path/to/schema.xsd', { autoLink: true });
1343
+ * // linked.$imports contains actual Schema objects
1344
+ *
1345
+ * // Resolve - flatten everything into one schema
1346
+ * const resolved = loadSchema('/path/to/schema.xsd', { autoResolve: true });
1347
+ * // resolved has all types merged, no $imports/$includes
1348
+ * ```
1349
+ */
1350
+ function loadSchema(schemaPath, options = {}) {
1351
+ const { basePath = dirname(schemaPath), loader = defaultLoader, autoLink = false, autoResolve = false, throwOnMissing = false } = options;
1352
+ const content = loader(schemaPath, basePath);
1353
+ if (!content) throw new Error(`Failed to load schema: ${schemaPath}`);
1354
+ let schema = parseXsd(content);
1355
+ Object.assign(schema, { $filename: schemaPath });
1356
+ if (autoLink || autoResolve) linkSchema(schema, {
1357
+ basePath,
1358
+ loader,
1359
+ throwOnMissing
1360
+ });
1361
+ if (autoResolve) schema = resolveSchema(schema);
1362
+ return schema;
1363
+ }
1364
+ /**
1365
+ * Load and parse XSD content from a string.
1366
+ */
1367
+ function parseSchemaContent(content, filename) {
1368
+ const schema = parseXsd(content);
1369
+ if (filename) Object.assign(schema, { $filename: filename });
1370
+ return schema;
1371
+ }
1372
+ /**
1373
+ * Create a schema loader function that can be passed to the resolver.
1374
+ * The resolver will call this to load schemas referenced by schemaLocation.
1375
+ */
1376
+ function createSchemaLoader(basePath, loader = defaultLoader) {
1377
+ const cache = /* @__PURE__ */ new Map();
1378
+ return (schemaLocation) => {
1379
+ const fullPath = resolve(basePath, schemaLocation);
1380
+ const cached = cache.get(fullPath);
1381
+ if (cached) return cached;
1382
+ const content = loader(schemaLocation, basePath);
1383
+ if (!content) return null;
1384
+ const schema = parseXsd(content);
1385
+ Object.assign(schema, { $filename: schemaLocation });
1386
+ cache.set(fullPath, schema);
1387
+ return schema;
1388
+ };
1389
+ }
1390
+ /**
1391
+ * Link a schema by resolving all schemaLocation references.
1392
+ *
1393
+ * Processes:
1394
+ * - xs:import → populates $imports
1395
+ * - xs:include → populates $includes
1396
+ * - xs:redefine → loads base schema, keeps redefinitions in redefine array
1397
+ * - xs:override → loads base schema, keeps overrides in override array
1398
+ *
1399
+ * @param schema - Schema to link (will be mutated with $imports/$includes)
1400
+ * @param options - Link options including basePath for resolving paths
1401
+ * @returns The same schema with $imports and $includes populated
1402
+ *
1403
+ * @example
1404
+ * ```typescript
1405
+ * const schema = parseXsd(xsdContent);
1406
+ * linkSchema(schema, { basePath: '/path/to/xsd/files' });
1407
+ * // schema.$imports and schema.$includes are now populated
1408
+ * ```
1409
+ */
1410
+ function linkSchema(schema, options) {
1411
+ const { basePath, loader = defaultLoader, throwOnMissing = true } = options;
1412
+ const cache = /* @__PURE__ */ new Map();
1413
+ const inProgress = /* @__PURE__ */ new Set();
1414
+ const loadAndLink = (schemaLocation, currentBasePath) => {
1415
+ const fullPath = resolve(currentBasePath, schemaLocation);
1416
+ const cached = cache.get(fullPath);
1417
+ if (cached) return cached;
1418
+ if (inProgress.has(fullPath)) return cache.get(fullPath) ?? null;
1419
+ const content = loader(schemaLocation, currentBasePath);
1420
+ if (!content) {
1421
+ if (throwOnMissing) throw new Error(`Failed to load schema: ${schemaLocation} (resolved: ${fullPath})`);
1422
+ return null;
1423
+ }
1424
+ const loadedSchema = parseXsd(content);
1425
+ Object.assign(loadedSchema, { $filename: schemaLocation });
1426
+ inProgress.add(fullPath);
1427
+ cache.set(fullPath, loadedSchema);
1428
+ const newBasePath = dirname(fullPath);
1429
+ linkSchemaInternal(loadedSchema, newBasePath);
1430
+ inProgress.delete(fullPath);
1431
+ return loadedSchema;
1432
+ };
1433
+ const linkSchemaInternal = (s, currentBasePath) => {
1434
+ const imports = [];
1435
+ const includes = [];
1436
+ if (s.import) {
1437
+ for (const imp of s.import) if (imp.schemaLocation) {
1438
+ const linked = loadAndLink(imp.schemaLocation, currentBasePath);
1439
+ if (linked) imports.push(linked);
1440
+ }
1441
+ }
1442
+ if (s.include) {
1443
+ for (const inc of s.include) if (inc.schemaLocation) {
1444
+ const linked = loadAndLink(inc.schemaLocation, currentBasePath);
1445
+ if (linked) includes.push(linked);
1446
+ }
1447
+ }
1448
+ if (s.redefine) {
1449
+ for (const redef of s.redefine) if (redef.schemaLocation) {
1450
+ const linked = loadAndLink(redef.schemaLocation, currentBasePath);
1451
+ if (linked) Object.assign(redef, { $schema: linked });
1452
+ }
1453
+ }
1454
+ if (s.override) {
1455
+ for (const ovr of s.override) if (ovr.schemaLocation) {
1456
+ const linked = loadAndLink(ovr.schemaLocation, currentBasePath);
1457
+ if (linked) Object.assign(ovr, { $schema: linked });
1458
+ }
1459
+ }
1460
+ if (imports.length > 0) Object.assign(s, { $imports: imports });
1461
+ if (includes.length > 0) Object.assign(s, { $includes: includes });
1462
+ };
1463
+ linkSchemaInternal(schema, basePath);
1464
+ return schema;
1465
+ }
1466
+ /**
1467
+ * Load and link a schema from a file path.
1468
+ * Convenience function that combines loadSchema + linkSchema.
1469
+ *
1470
+ * @param schemaPath - Path to the XSD file
1471
+ * @param options - Optional loader options
1472
+ * @returns Fully linked schema with $imports and $includes populated
1473
+ *
1474
+ * @example
1475
+ * ```typescript
1476
+ * const schema = loadAndLinkSchema('/path/to/schema.xsd');
1477
+ * // schema.$imports and schema.$includes are populated
1478
+ * // Ready for type inference or resolution
1479
+ * ```
1480
+ */
1481
+ function loadAndLinkSchema(schemaPath, options = {}) {
1482
+ const basePath = dirname(schemaPath);
1483
+ return linkSchema(loadSchema(schemaPath, {
1484
+ ...options,
1485
+ basePath
1486
+ }), {
1487
+ basePath,
1488
+ loader: options.loader
1489
+ });
1490
+ }
1491
+
1492
+ //#endregion
1493
+ //#region src/codegen/runner.ts
1494
+ /**
1495
+ * Config Runner
1496
+ *
1497
+ * Executes the generator pipeline based on configuration.
1498
+ */
1499
+ /**
1500
+ * Run the codegen pipeline
1501
+ */
1502
+ async function runCodegen(config, options) {
1503
+ const { rootDir, dryRun = false, verbose = false } = options;
1504
+ const result = {
1505
+ files: [],
1506
+ schemas: [],
1507
+ errors: []
1508
+ };
1509
+ const log = verbose ? console.log.bind(console) : () => {};
1510
+ const sources = {};
1511
+ for (const [name, sourceConfig] of Object.entries(config.sources)) {
1512
+ const xsdDir = isAbsolute(sourceConfig.xsdDir) ? sourceConfig.xsdDir : join(rootDir, sourceConfig.xsdDir);
1513
+ let schemas = sourceConfig.schemas;
1514
+ if (sourceConfig.autoLink) schemas = discoverDependentSchemas(sourceConfig.schemas, xsdDir, log);
1515
+ sources[name] = {
1516
+ name,
1517
+ xsdDir,
1518
+ outputDir: isAbsolute(sourceConfig.outputDir) ? sourceConfig.outputDir : join(rootDir, sourceConfig.outputDir),
1519
+ schemas
1520
+ };
1521
+ }
1522
+ const setupCtx = {
1523
+ sources,
1524
+ rootDir
1525
+ };
1526
+ if (config.clean) {
1527
+ log(`\n🧹 Cleaning output directories...`);
1528
+ for (const source of Object.values(sources)) if (existsSync(source.outputDir)) {
1529
+ rmSync(source.outputDir, {
1530
+ recursive: true,
1531
+ force: true
1532
+ });
1533
+ log(` ✅ Cleaned ${relative(rootDir, source.outputDir)}`);
1534
+ }
1535
+ }
1536
+ if (config.beforeAll) {
1537
+ log(`\n🔧 Running beforeAll hook...`);
1538
+ await config.beforeAll({
1539
+ sources,
1540
+ rootDir
1541
+ });
1542
+ }
1543
+ for (const generator of config.generators) if (generator.setup) {
1544
+ log(`[${generator.name}] Running setup...`);
1545
+ await generator.setup(setupCtx);
1546
+ }
1547
+ const processedSchemas = /* @__PURE__ */ new Map();
1548
+ const globalAllSchemas = /* @__PURE__ */ new Map();
1549
+ /**
1550
+ * Recursively discover and parse schemas referenced via xs:include or xs:redefine.
1551
+ * This ensures schemas like types/devc.xsd are in globalAllSchemas when devc.xsd references them.
1552
+ *
1553
+ * @param schema - The parsed schema object
1554
+ * @param xsdDir - The root XSD directory (e.g., '.xsd')
1555
+ * @param currentXsdPath - The path of the current XSD file (for resolving relative paths)
1556
+ * @param sourceName - The source name for logging
1557
+ * @param discovered - Set of already discovered schema names
1558
+ */
1559
+ function discoverReferencedSchemas(schema, xsdDir, currentXsdPath, sourceName, discovered = /* @__PURE__ */ new Set()) {
1560
+ const includes = schema.include;
1561
+ const redefines = schema.redefine;
1562
+ const refs = [...includes ?? [], ...redefines ?? []];
1563
+ for (const ref of refs) {
1564
+ if (!ref.schemaLocation) continue;
1565
+ const schemaNameWithPath = ref.schemaLocation.replace(/\.xsd$/, "");
1566
+ if (discovered.has(schemaNameWithPath) || globalAllSchemas.has(schemaNameWithPath)) continue;
1567
+ discovered.add(schemaNameWithPath);
1568
+ const currentXsdDir = dirname(currentXsdPath);
1569
+ const refXsdPath = join(currentXsdDir, ref.schemaLocation);
1570
+ if (!existsSync(refXsdPath)) {
1571
+ log(` ⚠️ Referenced schema not found: ${ref.schemaLocation} (resolved from ${currentXsdDir})`);
1572
+ continue;
1573
+ }
1574
+ try {
1575
+ const refXsdContent = readFileSync(refXsdPath, "utf-8");
1576
+ const refSchema = parseXsd(refXsdContent);
1577
+ refSchema.$filename = ref.schemaLocation;
1578
+ const refSchemaInfo = {
1579
+ name: schemaNameWithPath,
1580
+ xsdContent: refXsdContent,
1581
+ schema: refSchema,
1582
+ sourceName,
1583
+ xsdPath: refXsdPath
1584
+ };
1585
+ globalAllSchemas.set(schemaNameWithPath, refSchemaInfo);
1586
+ log(` 📎 Auto-discovered: ${schemaNameWithPath}`);
1587
+ discoverReferencedSchemas(refSchema, xsdDir, refXsdPath, sourceName, discovered);
1588
+ } catch (error) {
1589
+ const err = error instanceof Error ? error : new Error(String(error));
1590
+ log(` ⚠️ Failed to parse referenced schema ${ref.schemaLocation}: ${err.message}`);
1591
+ }
1592
+ }
1593
+ }
1594
+ for (const [sourceName, source] of Object.entries(sources)) {
1595
+ log(`\n📦 Processing source: ${sourceName}`);
1596
+ const schemaInfos = [];
1597
+ for (const schemaName of source.schemas) {
1598
+ const xsdPath = join(source.xsdDir, `${schemaName}.xsd`);
1599
+ if (!existsSync(xsdPath)) {
1600
+ log(` ⚠️ Skipping ${schemaName} - XSD not found`);
1601
+ continue;
1602
+ }
1603
+ try {
1604
+ const xsdContent = readFileSync(xsdPath, "utf-8");
1605
+ const schema = parseXsd(xsdContent);
1606
+ schema.$filename = `${schemaName}.xsd`;
1607
+ const basePath = dirname(xsdPath);
1608
+ linkSchema(schema, {
1609
+ basePath,
1610
+ throwOnMissing: false
1611
+ });
1612
+ const schemaInfo = {
1613
+ name: schemaName,
1614
+ xsdContent,
1615
+ schema,
1616
+ sourceName,
1617
+ xsdPath
1618
+ };
1619
+ schemaInfos.push(schemaInfo);
1620
+ globalAllSchemas.set(schemaName, schemaInfo);
1621
+ result.schemas.push({
1622
+ name: schemaName,
1623
+ source: sourceName
1624
+ });
1625
+ discoverReferencedSchemas(schema, source.xsdDir, xsdPath, sourceName);
1626
+ } catch (error) {
1627
+ const err = error instanceof Error ? error : new Error(String(error));
1628
+ log(` ❌ Failed to parse ${schemaName}: ${err.message}`);
1629
+ result.errors.push({
1630
+ schema: schemaName,
1631
+ source: sourceName,
1632
+ error: err
1633
+ });
1634
+ }
1635
+ }
1636
+ processedSchemas.set(sourceName, schemaInfos);
1637
+ }
1638
+ for (const [sourceName, source] of Object.entries(sources)) {
1639
+ const schemaInfos = processedSchemas.get(sourceName) ?? [];
1640
+ for (const schemaInfo of schemaInfos) {
1641
+ const transformCtx = {
1642
+ schema: schemaInfo,
1643
+ source,
1644
+ allSchemas: globalAllSchemas,
1645
+ allSources: sources,
1646
+ rootDir,
1647
+ resolveImport: createImportResolver(schemaInfo, source, sources, config)
1648
+ };
1649
+ for (const generator of config.generators) if (generator.transform) try {
1650
+ const files = await generator.transform(transformCtx);
1651
+ for (const file of files) {
1652
+ const fullPath = join(source.outputDir, file.path);
1653
+ if (!dryRun) {
1654
+ mkdirSync(dirname(fullPath), { recursive: true });
1655
+ writeFileSync(fullPath, file.content);
1656
+ }
1657
+ result.files.push({
1658
+ path: fullPath,
1659
+ source: sourceName
1660
+ });
1661
+ log(` ✅ [${generator.name}] Generated ${file.path}`);
1662
+ }
1663
+ } catch (error) {
1664
+ const err = error instanceof Error ? error : new Error(String(error));
1665
+ log(` ❌ [${generator.name}] Failed ${schemaInfo.name}: ${err.message}`);
1666
+ result.errors.push({
1667
+ schema: schemaInfo.name,
1668
+ source: sourceName,
1669
+ error: err
1670
+ });
1671
+ }
1672
+ }
1673
+ }
1674
+ const finalizeCtx = {
1675
+ processedSchemas,
1676
+ sources,
1677
+ rootDir
1678
+ };
1679
+ for (const generator of config.generators) if (generator.finalize) try {
1680
+ log(`\n[${generator.name}] Running finalize...`);
1681
+ const files = await generator.finalize(finalizeCtx);
1682
+ for (const file of files) for (const [sourceName, source] of Object.entries(sources)) {
1683
+ const fullPath = join(source.outputDir, file.path);
1684
+ if (!dryRun) {
1685
+ mkdirSync(dirname(fullPath), { recursive: true });
1686
+ writeFileSync(fullPath, file.content);
1687
+ }
1688
+ result.files.push({
1689
+ path: fullPath,
1690
+ source: sourceName
1691
+ });
1692
+ log(` ✅ [${generator.name}] Generated ${file.path} for ${sourceName}`);
1693
+ }
1694
+ } catch (error) {
1695
+ const err = error instanceof Error ? error : new Error(String(error));
1696
+ log(` ❌ [${generator.name}] Finalize failed: ${err.message}`);
1697
+ result.errors.push({ error: err });
1698
+ }
1699
+ if (config.afterAll) {
1700
+ log(`\n🔧 Running afterAll hook...`);
1701
+ const afterAllCtx = {
1702
+ sources,
1703
+ rootDir,
1704
+ processedSchemas,
1705
+ generatedFiles: result.files.map((f) => ({
1706
+ path: f.path,
1707
+ content: ""
1708
+ }))
1709
+ };
1710
+ const extraFiles = await config.afterAll(afterAllCtx);
1711
+ if (extraFiles && Array.isArray(extraFiles)) for (const file of extraFiles) {
1712
+ const fullPath = join(rootDir, file.path);
1713
+ if (!dryRun) {
1714
+ mkdirSync(dirname(fullPath), { recursive: true });
1715
+ writeFileSync(fullPath, file.content);
1716
+ }
1717
+ result.files.push({
1718
+ path: fullPath,
1719
+ source: "afterAll"
1720
+ });
1721
+ log(` ✅ [afterAll] Generated ${file.path}`);
1722
+ }
1723
+ }
1724
+ return result;
1725
+ }
1726
+ function createImportResolver(currentSchema, currentSource, allSources, config) {
1727
+ const ext = config.importExtension ?? "";
1728
+ return (schemaLocation) => {
1729
+ const schemaPath = schemaLocation.replace(/\.xsd$/, "");
1730
+ const schemaBaseName = schemaPath.replace(/^.*\//, "");
1731
+ const currentSchemaDir = dirname(currentSchema.name);
1732
+ const normalizedPath = (currentSchemaDir !== "." ? join(currentSchemaDir, schemaPath).replaceAll(/\\/g, "/") : schemaPath).split("/").reduce((acc, part) => {
1733
+ if (part === "..") acc.pop();
1734
+ else if (part !== ".") acc.push(part);
1735
+ return acc;
1736
+ }, []).join("/");
1737
+ if (currentSource.schemas.includes(normalizedPath)) {
1738
+ const fromDir = dirname(currentSchema.name);
1739
+ const toPath = normalizedPath;
1740
+ const relImport = fromDir === dirname(toPath) ? `./${basename(toPath)}${ext}` : relative(fromDir || ".", toPath).replaceAll(/\\/g, "/") || `./${basename(toPath)}`;
1741
+ return relImport.startsWith(".") ? `${relImport}${ext}` : `./${relImport}${ext}`;
1742
+ }
1743
+ if (currentSource.schemas.includes(schemaPath)) return `./${schemaPath}${ext}`;
1744
+ if (currentSource.schemas.includes(schemaBaseName)) return `./${schemaBaseName}${ext}`;
1745
+ for (const [sourceName, source] of Object.entries(allSources)) {
1746
+ if (sourceName === currentSource.name) continue;
1747
+ if (source.schemas.includes(normalizedPath)) return `${relative(currentSource.outputDir, source.outputDir)}/${normalizedPath}${ext}`.replaceAll(/\\/g, "/");
1748
+ if (source.schemas.includes(schemaPath)) return `${relative(currentSource.outputDir, source.outputDir)}/${schemaPath}${ext}`.replaceAll(/\\/g, "/");
1749
+ if (source.schemas.includes(schemaBaseName)) return `${relative(currentSource.outputDir, source.outputDir)}/${schemaBaseName}${ext}`.replaceAll(/\\/g, "/");
1750
+ }
1751
+ return null;
1752
+ };
1753
+ }
1754
+ /**
1755
+ * Discover all dependent schemas by recursively parsing XSD files
1756
+ * and extracting schemaLocation from xs:import, xs:include, xs:redefine
1757
+ */
1758
+ function discoverDependentSchemas(entrySchemas, xsdDir, log) {
1759
+ const discovered = /* @__PURE__ */ new Set();
1760
+ const queue = [...entrySchemas];
1761
+ while (queue.length > 0) {
1762
+ const schemaName = queue.shift();
1763
+ if (!schemaName) continue;
1764
+ if (discovered.has(schemaName)) continue;
1765
+ const xsdPath = join(xsdDir, `${schemaName}.xsd`);
1766
+ if (!existsSync(xsdPath)) throw new Error(`Schema not found: ${schemaName}.xsd (resolved: ${xsdPath})`);
1767
+ discovered.add(schemaName);
1768
+ try {
1769
+ const xsdContent = readFileSync(xsdPath, "utf-8");
1770
+ const deps = extractSchemaLocations(parseXsd(xsdContent), xsdDir, schemaName);
1771
+ for (const dep of deps) if (!discovered.has(dep)) {
1772
+ queue.push(dep);
1773
+ log(` 🔗 Discovered dependency: ${dep} (from ${schemaName})`);
1774
+ }
1775
+ } catch {
1776
+ log(` ❌ Failed to parse ${schemaName} for dependency discovery`);
1777
+ }
1778
+ }
1779
+ return Array.from(discovered);
1780
+ }
1781
+ /**
1782
+ * Extract schema names from schemaLocation attributes
1783
+ */
1784
+ function extractSchemaLocations(schema, xsdDir, currentSchema) {
1785
+ const locations = [];
1786
+ const currentDir = dirname(join(xsdDir, `${currentSchema}.xsd`));
1787
+ const imports = schema.import;
1788
+ if (imports) {
1789
+ for (const imp of imports) if (imp.schemaLocation) {
1790
+ const name = resolveSchemaName(imp.schemaLocation, currentDir, xsdDir);
1791
+ if (name) locations.push(name);
1792
+ }
1793
+ }
1794
+ const includes = schema.include;
1795
+ if (includes) {
1796
+ for (const inc of includes) if (inc.schemaLocation) {
1797
+ const name = resolveSchemaName(inc.schemaLocation, currentDir, xsdDir);
1798
+ if (name) locations.push(name);
1799
+ }
1800
+ }
1801
+ const redefines = schema.redefine;
1802
+ if (redefines) {
1803
+ for (const red of redefines) if (red.schemaLocation) {
1804
+ const name = resolveSchemaName(red.schemaLocation, currentDir, xsdDir);
1805
+ if (name) locations.push(name);
1806
+ }
1807
+ }
1808
+ return locations;
1809
+ }
1810
+ /**
1811
+ * Resolve schemaLocation to a schema name relative to xsdDir
1812
+ */
1813
+ function resolveSchemaName(schemaLocation, currentDir, xsdDir) {
1814
+ const fullPath = join(currentDir, schemaLocation);
1815
+ const name = relative(xsdDir, fullPath).replace(/\.xsd$/, "");
1816
+ if (existsSync(fullPath)) return name;
1817
+ return null;
1818
+ }
1819
+
1820
+ //#endregion
1821
+ export { getLocalName as _, loadAndLinkSchema as a, getSubstitutes as c, SchemaTraverser as d, resolveSchemaTypes as f, getChildElements as g, getAttributeValue as h, linkSchema as i, resolveSchema as l, getAllChildElements as m, createSchemaLoader as n, loadSchema as o, parseXsd as p, defaultLoader as r, parseSchemaContent as s, runCodegen as t, SchemaResolver as u, getTextContent as v };
1822
+ //# sourceMappingURL=runner-BSGqj8LM.mjs.map