@abapify/ts-xsd 0.4.33 → 0.4.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -320
- package/dist/codegen/cli.mjs +6 -4
- package/dist/codegen/cli.mjs.map +1 -1
- package/dist/{generate-DQJ38rjv.mjs → generate-BWLnwHUW.mjs} +38 -33
- package/dist/generate-BWLnwHUW.mjs.map +1 -0
- package/dist/generators/index.d.mts +1 -1
- package/dist/generators/index.mjs +130 -116
- package/dist/generators/index.mjs.map +1 -1
- package/dist/index.d.mts +6 -4
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +495 -368
- package/dist/index.mjs.map +1 -1
- package/dist/{runner-BGNA8Sl-.mjs → runner-BZNOc_YZ.mjs} +439 -334
- package/dist/runner-BZNOc_YZ.mjs.map +1 -0
- package/dist/{runner-CDEKB5AE.d.mts → runner-x86T9IvM.d.mts} +5 -5
- package/dist/{runner-CDEKB5AE.d.mts.map → runner-x86T9IvM.d.mts.map} +1 -1
- package/dist/{types-DVn3w5cv.mjs → types-BAx8yQfm.mjs} +152 -116
- package/dist/types-BAx8yQfm.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/generate-DQJ38rjv.mjs.map +0 -1
- package/dist/runner-BGNA8Sl-.mjs.map +0 -1
- package/dist/types-DVn3w5cv.mjs.map +0 -1
|
@@ -15,10 +15,7 @@ function isElement(node) {
|
|
|
15
15
|
*/
|
|
16
16
|
function getAttributeValue(node, name) {
|
|
17
17
|
if (node.hasAttribute(name)) return node.getAttribute(name);
|
|
18
|
-
for (
|
|
19
|
-
const attr = node.attributes[i];
|
|
20
|
-
if ((attr.localName || attr.name.split(":").pop()) === name) return attr.value;
|
|
21
|
-
}
|
|
18
|
+
for (const attr of node.attributes) if ((attr.localName || attr.name.split(":").pop()) === name) return attr.value;
|
|
22
19
|
return null;
|
|
23
20
|
}
|
|
24
21
|
/**
|
|
@@ -26,11 +23,8 @@ function getAttributeValue(node, name) {
|
|
|
26
23
|
*/
|
|
27
24
|
function getChildElements(parent, name) {
|
|
28
25
|
const result = [];
|
|
29
|
-
for (
|
|
30
|
-
|
|
31
|
-
if (isElement(child)) {
|
|
32
|
-
if ((child.localName || child.tagName.split(":").pop()) === name) result.push(child);
|
|
33
|
-
}
|
|
26
|
+
for (const child of parent.childNodes) if (isElement(child)) {
|
|
27
|
+
if ((child.localName || child.tagName.split(":").pop()) === name) result.push(child);
|
|
34
28
|
}
|
|
35
29
|
return result;
|
|
36
30
|
}
|
|
@@ -39,10 +33,7 @@ function getChildElements(parent, name) {
|
|
|
39
33
|
*/
|
|
40
34
|
function getAllChildElements(parent) {
|
|
41
35
|
const result = [];
|
|
42
|
-
for (
|
|
43
|
-
const child = parent.childNodes[i];
|
|
44
|
-
if (isElement(child)) result.push(child);
|
|
45
|
-
}
|
|
36
|
+
for (const child of parent.childNodes) if (isElement(child)) result.push(child);
|
|
46
37
|
return result;
|
|
47
38
|
}
|
|
48
39
|
/**
|
|
@@ -50,10 +41,7 @@ function getAllChildElements(parent) {
|
|
|
50
41
|
*/
|
|
51
42
|
function getTextContent(node) {
|
|
52
43
|
let text = "";
|
|
53
|
-
for (
|
|
54
|
-
const child = node.childNodes[i];
|
|
55
|
-
if (child.nodeType === 3) text += child.textContent || "";
|
|
56
|
-
}
|
|
44
|
+
for (const child of node.childNodes) if (child.nodeType === 3) text += child.textContent || "";
|
|
57
45
|
return text.trim();
|
|
58
46
|
}
|
|
59
47
|
/**
|
|
@@ -827,8 +815,7 @@ function parseAnnotationChild(el, result) {
|
|
|
827
815
|
function extractXmlns(el) {
|
|
828
816
|
const xmlns = {};
|
|
829
817
|
let hasXmlns = false;
|
|
830
|
-
for (
|
|
831
|
-
const attr = el.attributes[i];
|
|
818
|
+
for (const attr of el.attributes) {
|
|
832
819
|
const name = attr.name;
|
|
833
820
|
const value = attr.value;
|
|
834
821
|
if (name === "xmlns") {
|
|
@@ -924,12 +911,12 @@ var SchemaTraverser = class {
|
|
|
924
911
|
this.onLeaveSchema(schema);
|
|
925
912
|
}
|
|
926
913
|
traverseSchemaChildren(schema) {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
914
|
+
for (const ct of schema.complexType ?? []) this.onComplexType(ct);
|
|
915
|
+
for (const st of schema.simpleType ?? []) this.onSimpleType(st);
|
|
916
|
+
for (const element of schema.element ?? []) this.onElement(element);
|
|
917
|
+
for (const attr of schema.attribute ?? []) this.onAttribute(attr);
|
|
918
|
+
for (const group of schema.group ?? []) this.onGroup(group);
|
|
919
|
+
for (const group of schema.attributeGroup ?? []) this.onAttributeGroup(group);
|
|
933
920
|
}
|
|
934
921
|
traverseRedefines(schema) {
|
|
935
922
|
if (!schema.redefine) return;
|
|
@@ -937,28 +924,34 @@ var SchemaTraverser = class {
|
|
|
937
924
|
this.source = "redefine";
|
|
938
925
|
for (const redefine of schema.redefine) {
|
|
939
926
|
this.onRedefine(redefine);
|
|
940
|
-
|
|
941
|
-
if (redefine.simpleType) for (const st of redefine.simpleType) this.onSimpleType(st);
|
|
942
|
-
if (redefine.group) for (const group of redefine.group) this.onGroup(group);
|
|
943
|
-
if (redefine.attributeGroup) for (const group of redefine.attributeGroup) this.onAttributeGroup(group);
|
|
927
|
+
this.traverseRedefineChildren(redefine);
|
|
944
928
|
}
|
|
945
929
|
this.source = prevSource;
|
|
946
930
|
}
|
|
931
|
+
traverseRedefineChildren(redefine) {
|
|
932
|
+
for (const ct of redefine.complexType ?? []) this.onComplexType(ct);
|
|
933
|
+
for (const st of redefine.simpleType ?? []) this.onSimpleType(st);
|
|
934
|
+
for (const group of redefine.group ?? []) this.onGroup(group);
|
|
935
|
+
for (const group of redefine.attributeGroup ?? []) this.onAttributeGroup(group);
|
|
936
|
+
}
|
|
947
937
|
traverseOverrides(schema) {
|
|
948
938
|
if (!schema.override) return;
|
|
949
939
|
const prevSource = this.source;
|
|
950
940
|
this.source = "override";
|
|
951
941
|
for (const override of schema.override) {
|
|
952
942
|
this.onOverride(override);
|
|
953
|
-
|
|
954
|
-
if (override.simpleType) for (const st of override.simpleType) this.onSimpleType(st);
|
|
955
|
-
if (override.element) for (const element of override.element) this.onElement(element);
|
|
956
|
-
if (override.attribute) for (const attr of override.attribute) this.onAttribute(attr);
|
|
957
|
-
if (override.group) for (const group of override.group) this.onGroup(group);
|
|
958
|
-
if (override.attributeGroup) for (const group of override.attributeGroup) this.onAttributeGroup(group);
|
|
943
|
+
this.traverseOverrideChildren(override);
|
|
959
944
|
}
|
|
960
945
|
this.source = prevSource;
|
|
961
946
|
}
|
|
947
|
+
traverseOverrideChildren(override) {
|
|
948
|
+
for (const ct of override.complexType ?? []) this.onComplexType(ct);
|
|
949
|
+
for (const st of override.simpleType ?? []) this.onSimpleType(st);
|
|
950
|
+
for (const element of override.element ?? []) this.onElement(element);
|
|
951
|
+
for (const attr of override.attribute ?? []) this.onAttribute(attr);
|
|
952
|
+
for (const group of override.group ?? []) this.onGroup(group);
|
|
953
|
+
for (const group of override.attributeGroup ?? []) this.onAttributeGroup(group);
|
|
954
|
+
}
|
|
962
955
|
traverseIncludes(schema, depth) {
|
|
963
956
|
if (!this.options.includeIncludes || !schema.$includes) return;
|
|
964
957
|
for (const included of schema.$includes) this.traverseSchema(included, "include", depth + 1);
|
|
@@ -1122,17 +1115,7 @@ function resolveSchema(schema, options = {}) {
|
|
|
1122
1115
|
includeImports: resolveImports,
|
|
1123
1116
|
includeIncludes: resolveIncludes
|
|
1124
1117
|
});
|
|
1125
|
-
|
|
1126
|
-
if (filterToRootElements) {
|
|
1127
|
-
const referencedElements = /* @__PURE__ */ new Set();
|
|
1128
|
-
for (const el of collector.elements.values()) collectElementRefs(el, referencedElements);
|
|
1129
|
-
for (const ct of collector.complexTypes.values()) collectElementRefsFromType(ct, referencedElements);
|
|
1130
|
-
elements = Array.from(collector.elements.values()).filter((el) => {
|
|
1131
|
-
if (el.abstract === true) return false;
|
|
1132
|
-
if (referencedElements.has(el.name)) return false;
|
|
1133
|
-
return true;
|
|
1134
|
-
});
|
|
1135
|
-
} else elements = Array.from(collector.elements.values());
|
|
1118
|
+
const elements = selectElements(collector, filterToRootElements);
|
|
1136
1119
|
let resolvedComplexTypes = Array.from(collector.complexTypes.values());
|
|
1137
1120
|
if (expandExtensions) resolvedComplexTypes = resolvedComplexTypes.map((ct) => expandComplexTypeExtension(ct, collector.complexTypes));
|
|
1138
1121
|
if (expandSubstitutions) resolvedComplexTypes = resolvedComplexTypes.map((ct) => expandSubstitutionGroupsInType(ct, collector.elements, collector.substitutionGroups));
|
|
@@ -1151,6 +1134,22 @@ function resolveSchema(schema, options = {}) {
|
|
|
1151
1134
|
return resolved;
|
|
1152
1135
|
}
|
|
1153
1136
|
/**
|
|
1137
|
+
* Determine which elements to include in the resolved schema.
|
|
1138
|
+
*/
|
|
1139
|
+
function selectElements(collector, filterToRootElements) {
|
|
1140
|
+
if (!filterToRootElements) return Array.from(collector.elements.values());
|
|
1141
|
+
const referencedElements = /* @__PURE__ */ new Set();
|
|
1142
|
+
for (const el of collector.elements.values()) collectElementRefs(el, referencedElements);
|
|
1143
|
+
for (const ct of collector.complexTypes.values()) collectElementRefsFromType(ct, referencedElements);
|
|
1144
|
+
return Array.from(collector.elements.values()).filter((el) => isRootElement(el, referencedElements));
|
|
1145
|
+
}
|
|
1146
|
+
/** An element is a root element when it is not abstract and not referenced. */
|
|
1147
|
+
function isRootElement(el, referencedElements) {
|
|
1148
|
+
if (el.abstract === true) return false;
|
|
1149
|
+
if (referencedElements.has(el.name)) return false;
|
|
1150
|
+
return true;
|
|
1151
|
+
}
|
|
1152
|
+
/**
|
|
1154
1153
|
* Expand complexContent/extension by merging base type properties.
|
|
1155
1154
|
* Uses a visited set to prevent infinite recursion on circular inheritance.
|
|
1156
1155
|
*/
|
|
@@ -1164,12 +1163,7 @@ function expandComplexTypeExtension(ct, allTypes, visited = /* @__PURE__ */ new
|
|
|
1164
1163
|
const mergedAttributes = [];
|
|
1165
1164
|
const baseName = stripNsPrefix(extension.base);
|
|
1166
1165
|
const baseType = allTypes.get(baseName);
|
|
1167
|
-
if (baseType && !visited.has(baseName))
|
|
1168
|
-
const expandedBase = expandComplexTypeExtension(baseType, allTypes, visited);
|
|
1169
|
-
collectElementsFromType(expandedBase, mergedElements);
|
|
1170
|
-
collectAnysFromType(expandedBase, mergedAnys);
|
|
1171
|
-
if (expandedBase.attribute) mergedAttributes.push(...expandedBase.attribute);
|
|
1172
|
-
}
|
|
1166
|
+
if (baseType && !visited.has(baseName)) mergeBaseTypeContent(baseType, allTypes, visited, mergedElements, mergedAnys, mergedAttributes);
|
|
1173
1167
|
collectElementsFromGroup(extension.sequence, mergedElements);
|
|
1174
1168
|
collectElementsFromGroup(extension.choice, mergedElements);
|
|
1175
1169
|
collectElementsFromGroup(extension.all, mergedElements);
|
|
@@ -1177,11 +1171,25 @@ function expandComplexTypeExtension(ct, allTypes, visited = /* @__PURE__ */ new
|
|
|
1177
1171
|
collectAnysFromGroup(extension.choice, mergedAnys);
|
|
1178
1172
|
collectAnysFromGroup(extension.all, mergedAnys);
|
|
1179
1173
|
if (extension.attribute) mergedAttributes.push(...extension.attribute);
|
|
1174
|
+
return buildFlattenedType(ct, mergedElements, mergedAnys, mergedAttributes);
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Recursively expand the base type and merge its content into the accumulators.
|
|
1178
|
+
*/
|
|
1179
|
+
function mergeBaseTypeContent(baseType, allTypes, visited, mergedElements, mergedAnys, mergedAttributes) {
|
|
1180
|
+
const expandedBase = expandComplexTypeExtension(baseType, allTypes, visited);
|
|
1181
|
+
collectElementsFromType(expandedBase, mergedElements);
|
|
1182
|
+
collectAnysFromType(expandedBase, mergedAnys);
|
|
1183
|
+
if (expandedBase.attribute) mergedAttributes.push(...expandedBase.attribute);
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Build the flattened complex type from the merged content,
|
|
1187
|
+
* copying over all other properties of the original type.
|
|
1188
|
+
*/
|
|
1189
|
+
function buildFlattenedType(ct, mergedElements, mergedAnys, mergedAttributes) {
|
|
1180
1190
|
const flattened = { name: ct.name };
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
...mergedAnys.length > 0 ? { any: mergedAnys } : {}
|
|
1184
|
-
};
|
|
1191
|
+
const all = buildFlattenedAll(mergedElements, mergedAnys);
|
|
1192
|
+
if (all) flattened.all = all;
|
|
1185
1193
|
if (mergedAttributes.length > 0) flattened.attribute = mergedAttributes;
|
|
1186
1194
|
for (const [key, value] of Object.entries(ct)) if (![
|
|
1187
1195
|
"name",
|
|
@@ -1194,6 +1202,15 @@ function expandComplexTypeExtension(ct, allTypes, visited = /* @__PURE__ */ new
|
|
|
1194
1202
|
return flattened;
|
|
1195
1203
|
}
|
|
1196
1204
|
/**
|
|
1205
|
+
* Build the flattened `all` content model, or undefined when there is no content.
|
|
1206
|
+
*/
|
|
1207
|
+
function buildFlattenedAll(mergedElements, mergedAnys) {
|
|
1208
|
+
const all = {};
|
|
1209
|
+
if (mergedElements.length > 0) all.element = mergedElements;
|
|
1210
|
+
if (mergedAnys.length > 0) all.any = mergedAnys;
|
|
1211
|
+
return Object.keys(all).length > 0 ? all : void 0;
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1197
1214
|
* Collect elements from a complex type's content model.
|
|
1198
1215
|
*/
|
|
1199
1216
|
function collectElementsFromType(ct, elements) {
|
|
@@ -1264,23 +1281,11 @@ function expandSubstitutionGroupsInGroup(group, allElements, substitutionGroups)
|
|
|
1264
1281
|
const expandedElements = [];
|
|
1265
1282
|
let hasChanges = false;
|
|
1266
1283
|
for (const el of group.element) {
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
for (const sub of substitutes) expandedElements.push({
|
|
1273
|
-
name: sub.name,
|
|
1274
|
-
type: sub.type,
|
|
1275
|
-
minOccurs: el.minOccurs ?? 0,
|
|
1276
|
-
maxOccurs: el.maxOccurs
|
|
1277
|
-
});
|
|
1278
|
-
hasChanges = true;
|
|
1279
|
-
continue;
|
|
1280
|
-
}
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
expandedElements.push(el);
|
|
1284
|
+
const substitutes = expandAbstractElementRef(el, allElements, substitutionGroups);
|
|
1285
|
+
if (substitutes) {
|
|
1286
|
+
expandedElements.push(...substitutes);
|
|
1287
|
+
hasChanges = true;
|
|
1288
|
+
} else expandedElements.push(el);
|
|
1284
1289
|
}
|
|
1285
1290
|
if (!hasChanges) return group;
|
|
1286
1291
|
return {
|
|
@@ -1289,6 +1294,23 @@ function expandSubstitutionGroupsInGroup(group, allElements, substitutionGroups)
|
|
|
1289
1294
|
};
|
|
1290
1295
|
}
|
|
1291
1296
|
/**
|
|
1297
|
+
* Expand a ref to an abstract element into its substitutes,
|
|
1298
|
+
* or return undefined when the element needs no expansion.
|
|
1299
|
+
*/
|
|
1300
|
+
function expandAbstractElementRef(el, allElements, substitutionGroups) {
|
|
1301
|
+
if (!el.ref) return void 0;
|
|
1302
|
+
const refName = stripNsPrefix(el.ref);
|
|
1303
|
+
if (!allElements.get(refName)?.abstract) return void 0;
|
|
1304
|
+
const substitutes = substitutionGroups.get(refName);
|
|
1305
|
+
if (!substitutes?.length) return void 0;
|
|
1306
|
+
return substitutes.map((sub) => ({
|
|
1307
|
+
name: sub.name,
|
|
1308
|
+
type: sub.type,
|
|
1309
|
+
minOccurs: el.minOccurs ?? 0,
|
|
1310
|
+
maxOccurs: el.maxOccurs
|
|
1311
|
+
}));
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1292
1314
|
* Get all substitutes for an abstract element.
|
|
1293
1315
|
*/
|
|
1294
1316
|
function getSubstitutes(abstractElementName, schema) {
|
|
@@ -1314,20 +1336,21 @@ function collectElementRefsFromType(ct, refs) {
|
|
|
1314
1336
|
"choice"
|
|
1315
1337
|
]) {
|
|
1316
1338
|
const group = record[groupKey];
|
|
1317
|
-
if (group?.element)
|
|
1318
|
-
const elements = group.element;
|
|
1319
|
-
for (const el of elements) {
|
|
1320
|
-
if (el.ref) {
|
|
1321
|
-
const refName = stripNsPrefix(el.ref);
|
|
1322
|
-
refs.add(refName);
|
|
1323
|
-
}
|
|
1324
|
-
if (el.complexType) collectElementRefsFromType(el.complexType, refs);
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1339
|
+
if (group?.element) collectElementRefsFromElements(group.element, refs);
|
|
1327
1340
|
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1341
|
+
const cc = record.complexContent;
|
|
1342
|
+
if (cc?.extension) collectElementRefsFromType(cc.extension, refs);
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Recursively collect element refs from a list of elements
|
|
1346
|
+
*/
|
|
1347
|
+
function collectElementRefsFromElements(elements, refs) {
|
|
1348
|
+
for (const el of elements) {
|
|
1349
|
+
if (el.ref) {
|
|
1350
|
+
const refName = stripNsPrefix(el.ref);
|
|
1351
|
+
refs.add(refName);
|
|
1352
|
+
}
|
|
1353
|
+
if (el.complexType) collectElementRefsFromType(el.complexType, refs);
|
|
1331
1354
|
}
|
|
1332
1355
|
}
|
|
1333
1356
|
|
|
@@ -1447,44 +1470,41 @@ function linkSchema(schema, options) {
|
|
|
1447
1470
|
Object.assign(loadedSchema, { $filename: schemaLocation });
|
|
1448
1471
|
inProgress.add(fullPath);
|
|
1449
1472
|
cache.set(fullPath, loadedSchema);
|
|
1450
|
-
|
|
1451
|
-
linkSchemaInternal(loadedSchema, newBasePath);
|
|
1473
|
+
linkSchemaInternal(loadedSchema, dirname(fullPath), loadAndLink);
|
|
1452
1474
|
inProgress.delete(fullPath);
|
|
1453
1475
|
return loadedSchema;
|
|
1454
1476
|
};
|
|
1455
|
-
|
|
1456
|
-
const imports = [];
|
|
1457
|
-
const includes = [];
|
|
1458
|
-
if (s.import) {
|
|
1459
|
-
for (const imp of s.import) if (imp.schemaLocation) {
|
|
1460
|
-
const linked = loadAndLink(imp.schemaLocation, currentBasePath);
|
|
1461
|
-
if (linked) imports.push(linked);
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
if (s.include) {
|
|
1465
|
-
for (const inc of s.include) if (inc.schemaLocation) {
|
|
1466
|
-
const linked = loadAndLink(inc.schemaLocation, currentBasePath);
|
|
1467
|
-
if (linked) includes.push(linked);
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
if (s.redefine) {
|
|
1471
|
-
for (const redef of s.redefine) if (redef.schemaLocation) {
|
|
1472
|
-
const linked = loadAndLink(redef.schemaLocation, currentBasePath);
|
|
1473
|
-
if (linked) Object.assign(redef, { $schema: linked });
|
|
1474
|
-
}
|
|
1475
|
-
}
|
|
1476
|
-
if (s.override) {
|
|
1477
|
-
for (const ovr of s.override) if (ovr.schemaLocation) {
|
|
1478
|
-
const linked = loadAndLink(ovr.schemaLocation, currentBasePath);
|
|
1479
|
-
if (linked) Object.assign(ovr, { $schema: linked });
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
if (imports.length > 0) Object.assign(s, { $imports: imports });
|
|
1483
|
-
if (includes.length > 0) Object.assign(s, { $includes: includes });
|
|
1484
|
-
};
|
|
1485
|
-
linkSchemaInternal(schema, basePath);
|
|
1477
|
+
linkSchemaInternal(schema, basePath, loadAndLink);
|
|
1486
1478
|
return schema;
|
|
1487
1479
|
}
|
|
1480
|
+
/** Process imports/includes/redefines/overrides and link their schemas. */
|
|
1481
|
+
function linkSchemaInternal(s, currentBasePath, loadAndLink) {
|
|
1482
|
+
const imports = loadLinkedSchemas(s.import, currentBasePath, loadAndLink);
|
|
1483
|
+
const includes = loadLinkedSchemas(s.include, currentBasePath, loadAndLink);
|
|
1484
|
+
attachBaseSchemas(s.redefine, currentBasePath, loadAndLink);
|
|
1485
|
+
attachBaseSchemas(s.override, currentBasePath, loadAndLink);
|
|
1486
|
+
if (imports.length > 0) Object.assign(s, { $imports: imports });
|
|
1487
|
+
if (includes.length > 0) Object.assign(s, { $includes: includes });
|
|
1488
|
+
}
|
|
1489
|
+
/** Load and link every referenced schema, skipping missing ones. */
|
|
1490
|
+
function loadLinkedSchemas(refs, currentBasePath, loadAndLink) {
|
|
1491
|
+
const linkedSchemas = [];
|
|
1492
|
+
for (const ref of refs ?? []) if (ref.schemaLocation) {
|
|
1493
|
+
const linked = loadAndLink(ref.schemaLocation, currentBasePath);
|
|
1494
|
+
if (linked) linkedSchemas.push(linked);
|
|
1495
|
+
}
|
|
1496
|
+
return linkedSchemas;
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Load the base schema of each redefine/override element
|
|
1500
|
+
* and attach it to the element as `$schema`.
|
|
1501
|
+
*/
|
|
1502
|
+
function attachBaseSchemas(refs, currentBasePath, loadAndLink) {
|
|
1503
|
+
for (const ref of refs ?? []) if (ref.schemaLocation) {
|
|
1504
|
+
const linked = loadAndLink(ref.schemaLocation, currentBasePath);
|
|
1505
|
+
if (linked) Object.assign(ref, { $schema: linked });
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1488
1508
|
/**
|
|
1489
1509
|
* Load and link a schema from a file path.
|
|
1490
1510
|
* Convenience function that combines loadSchema + linkSchema.
|
|
@@ -1528,32 +1548,12 @@ async function runCodegen(config, options) {
|
|
|
1528
1548
|
errors: []
|
|
1529
1549
|
};
|
|
1530
1550
|
const log = verbose ? console.log.bind(console) : () => {};
|
|
1531
|
-
const sources =
|
|
1532
|
-
for (const [name, sourceConfig] of Object.entries(config.sources)) {
|
|
1533
|
-
const xsdDir = isAbsolute(sourceConfig.xsdDir) ? sourceConfig.xsdDir : join(rootDir, sourceConfig.xsdDir);
|
|
1534
|
-
let schemas = sourceConfig.schemas;
|
|
1535
|
-
if (sourceConfig.autoLink) schemas = discoverDependentSchemas(sourceConfig.schemas, xsdDir, log);
|
|
1536
|
-
sources[name] = {
|
|
1537
|
-
name,
|
|
1538
|
-
xsdDir,
|
|
1539
|
-
outputDir: isAbsolute(sourceConfig.outputDir) ? sourceConfig.outputDir : join(rootDir, sourceConfig.outputDir),
|
|
1540
|
-
schemas
|
|
1541
|
-
};
|
|
1542
|
-
}
|
|
1551
|
+
const sources = buildSourceInfos(config, rootDir, log);
|
|
1543
1552
|
const setupCtx = {
|
|
1544
1553
|
sources,
|
|
1545
1554
|
rootDir
|
|
1546
1555
|
};
|
|
1547
|
-
if (config.clean)
|
|
1548
|
-
log(`\n🧹 Cleaning output directories...`);
|
|
1549
|
-
for (const source of Object.values(sources)) if (existsSync(source.outputDir)) {
|
|
1550
|
-
rmSync(source.outputDir, {
|
|
1551
|
-
recursive: true,
|
|
1552
|
-
force: true
|
|
1553
|
-
});
|
|
1554
|
-
log(` ✅ Cleaned ${relative(rootDir, source.outputDir)}`);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1556
|
+
if (config.clean) cleanOutputDirs(sources, rootDir, log);
|
|
1557
1557
|
if (config.beforeAll) {
|
|
1558
1558
|
log(`\n🔧 Running beforeAll hook...`);
|
|
1559
1559
|
await config.beforeAll({
|
|
@@ -1565,214 +1565,328 @@ async function runCodegen(config, options) {
|
|
|
1565
1565
|
log(`[${generator.name}] Running setup...`);
|
|
1566
1566
|
await generator.setup(setupCtx);
|
|
1567
1567
|
}
|
|
1568
|
+
const { processedSchemas, globalAllSchemas } = parseAllSchemas(sources, result, log);
|
|
1569
|
+
await runTransforms({
|
|
1570
|
+
config,
|
|
1571
|
+
sources,
|
|
1572
|
+
processedSchemas,
|
|
1573
|
+
globalAllSchemas,
|
|
1574
|
+
rootDir,
|
|
1575
|
+
dryRun,
|
|
1576
|
+
result,
|
|
1577
|
+
log
|
|
1578
|
+
});
|
|
1579
|
+
await runFinalize(config, sources, processedSchemas, rootDir, dryRun, result, log);
|
|
1580
|
+
await runAfterAll(config, sources, processedSchemas, rootDir, dryRun, result, log);
|
|
1581
|
+
return result;
|
|
1582
|
+
}
|
|
1583
|
+
/** Build source info map - expand schemas if autoLink is enabled. */
|
|
1584
|
+
function buildSourceInfos(config, rootDir, log) {
|
|
1585
|
+
const sources = {};
|
|
1586
|
+
for (const [name, sourceConfig] of Object.entries(config.sources)) {
|
|
1587
|
+
const xsdDir = isAbsolute(sourceConfig.xsdDir) ? sourceConfig.xsdDir : join(rootDir, sourceConfig.xsdDir);
|
|
1588
|
+
let schemas = sourceConfig.schemas;
|
|
1589
|
+
if (sourceConfig.autoLink) schemas = discoverDependentSchemas(sourceConfig.schemas, xsdDir, log);
|
|
1590
|
+
sources[name] = {
|
|
1591
|
+
name,
|
|
1592
|
+
xsdDir,
|
|
1593
|
+
outputDir: isAbsolute(sourceConfig.outputDir) ? sourceConfig.outputDir : join(rootDir, sourceConfig.outputDir),
|
|
1594
|
+
schemas
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
return sources;
|
|
1598
|
+
}
|
|
1599
|
+
/** Clean output directories if requested. */
|
|
1600
|
+
function cleanOutputDirs(sources, rootDir, log) {
|
|
1601
|
+
log(`\n🧹 Cleaning output directories...`);
|
|
1602
|
+
for (const source of Object.values(sources)) if (existsSync(source.outputDir)) {
|
|
1603
|
+
rmSync(source.outputDir, {
|
|
1604
|
+
recursive: true,
|
|
1605
|
+
force: true
|
|
1606
|
+
});
|
|
1607
|
+
log(` ✅ Cleaned ${relative(rootDir, source.outputDir)}`);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
/**
|
|
1611
|
+
* First pass: parse ALL schemas from ALL sources into a global map.
|
|
1612
|
+
* This is needed for cross-source type resolution (e.g., custom schemas importing SAP schemas).
|
|
1613
|
+
*/
|
|
1614
|
+
function parseAllSchemas(sources, result, log) {
|
|
1568
1615
|
const processedSchemas = /* @__PURE__ */ new Map();
|
|
1569
1616
|
const globalAllSchemas = /* @__PURE__ */ new Map();
|
|
1570
|
-
/**
|
|
1571
|
-
* Recursively discover and parse schemas referenced via xs:include or xs:redefine.
|
|
1572
|
-
* This ensures schemas like types/devc.xsd are in globalAllSchemas when devc.xsd references them.
|
|
1573
|
-
*
|
|
1574
|
-
* @param schema - The parsed schema object
|
|
1575
|
-
* @param xsdDir - The root XSD directory (e.g., '.xsd')
|
|
1576
|
-
* @param currentXsdPath - The path of the current XSD file (for resolving relative paths)
|
|
1577
|
-
* @param sourceName - The source name for logging
|
|
1578
|
-
* @param discovered - Set of already discovered schema names
|
|
1579
|
-
*/
|
|
1580
|
-
function discoverReferencedSchemas(schema, xsdDir, currentXsdPath, sourceName, discovered = /* @__PURE__ */ new Set()) {
|
|
1581
|
-
const includes = schema.include;
|
|
1582
|
-
const redefines = schema.redefine;
|
|
1583
|
-
const refs = [...includes ?? [], ...redefines ?? []];
|
|
1584
|
-
for (const ref of refs) {
|
|
1585
|
-
if (!ref.schemaLocation) continue;
|
|
1586
|
-
const schemaNameWithPath = ref.schemaLocation.replace(/\.xsd$/, "");
|
|
1587
|
-
if (discovered.has(schemaNameWithPath) || globalAllSchemas.has(schemaNameWithPath)) continue;
|
|
1588
|
-
discovered.add(schemaNameWithPath);
|
|
1589
|
-
const currentXsdDir = dirname(currentXsdPath);
|
|
1590
|
-
const refXsdPath = join(currentXsdDir, ref.schemaLocation);
|
|
1591
|
-
if (!existsSync(refXsdPath)) {
|
|
1592
|
-
log(` ⚠️ Referenced schema not found: ${ref.schemaLocation} (resolved from ${currentXsdDir})`);
|
|
1593
|
-
continue;
|
|
1594
|
-
}
|
|
1595
|
-
try {
|
|
1596
|
-
const refXsdContent = readFileSync(refXsdPath, "utf-8");
|
|
1597
|
-
const refSchema = parseXsd(refXsdContent);
|
|
1598
|
-
refSchema.$filename = ref.schemaLocation;
|
|
1599
|
-
const refSchemaInfo = {
|
|
1600
|
-
name: schemaNameWithPath,
|
|
1601
|
-
xsdContent: refXsdContent,
|
|
1602
|
-
schema: refSchema,
|
|
1603
|
-
sourceName,
|
|
1604
|
-
xsdPath: refXsdPath
|
|
1605
|
-
};
|
|
1606
|
-
globalAllSchemas.set(schemaNameWithPath, refSchemaInfo);
|
|
1607
|
-
log(` 📎 Auto-discovered: ${schemaNameWithPath}`);
|
|
1608
|
-
discoverReferencedSchemas(refSchema, xsdDir, refXsdPath, sourceName, discovered);
|
|
1609
|
-
} catch (error) {
|
|
1610
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1611
|
-
log(` ⚠️ Failed to parse referenced schema ${ref.schemaLocation}: ${err.message}`);
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
1615
1617
|
for (const [sourceName, source] of Object.entries(sources)) {
|
|
1616
1618
|
log(`\n📦 Processing source: ${sourceName}`);
|
|
1617
1619
|
const schemaInfos = [];
|
|
1618
1620
|
for (const schemaName of source.schemas) {
|
|
1619
|
-
const
|
|
1620
|
-
if (
|
|
1621
|
-
log(` ⚠️ Skipping ${schemaName} - XSD not found`);
|
|
1622
|
-
continue;
|
|
1623
|
-
}
|
|
1624
|
-
try {
|
|
1625
|
-
const xsdContent = readFileSync(xsdPath, "utf-8");
|
|
1626
|
-
const schema = parseXsd(xsdContent);
|
|
1627
|
-
schema.$filename = `${schemaName}.xsd`;
|
|
1628
|
-
const basePath = dirname(xsdPath);
|
|
1629
|
-
linkSchema(schema, {
|
|
1630
|
-
basePath,
|
|
1631
|
-
throwOnMissing: false
|
|
1632
|
-
});
|
|
1633
|
-
const schemaInfo = {
|
|
1634
|
-
name: schemaName,
|
|
1635
|
-
xsdContent,
|
|
1636
|
-
schema,
|
|
1637
|
-
sourceName,
|
|
1638
|
-
xsdPath
|
|
1639
|
-
};
|
|
1621
|
+
const schemaInfo = parseSchemaInfo(schemaName, source, sourceName, globalAllSchemas, result, log);
|
|
1622
|
+
if (schemaInfo) {
|
|
1640
1623
|
schemaInfos.push(schemaInfo);
|
|
1641
|
-
globalAllSchemas.set(schemaName, schemaInfo);
|
|
1642
1624
|
result.schemas.push({
|
|
1643
1625
|
name: schemaName,
|
|
1644
1626
|
source: sourceName
|
|
1645
1627
|
});
|
|
1646
|
-
discoverReferencedSchemas(schema, source.xsdDir, xsdPath, sourceName);
|
|
1647
|
-
} catch (error) {
|
|
1648
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1649
|
-
log(` ❌ Failed to parse ${schemaName}: ${err.message}`);
|
|
1650
|
-
result.errors.push({
|
|
1651
|
-
schema: schemaName,
|
|
1652
|
-
source: sourceName,
|
|
1653
|
-
error: err
|
|
1654
|
-
});
|
|
1655
1628
|
}
|
|
1656
1629
|
}
|
|
1657
1630
|
processedSchemas.set(sourceName, schemaInfos);
|
|
1658
1631
|
}
|
|
1632
|
+
return {
|
|
1633
|
+
processedSchemas,
|
|
1634
|
+
globalAllSchemas
|
|
1635
|
+
};
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Parse and link one schema, registering it and its referenced schemas.
|
|
1639
|
+
* Returns undefined (skipping without an error when the file is missing,
|
|
1640
|
+
* recording an error when parsing fails).
|
|
1641
|
+
*/
|
|
1642
|
+
function parseSchemaInfo(schemaName, source, sourceName, globalAllSchemas, result, log) {
|
|
1643
|
+
const xsdPath = join(source.xsdDir, `${schemaName}.xsd`);
|
|
1644
|
+
if (!existsSync(xsdPath)) {
|
|
1645
|
+
log(` ⚠️ Skipping ${schemaName} - XSD not found`);
|
|
1646
|
+
return;
|
|
1647
|
+
}
|
|
1648
|
+
try {
|
|
1649
|
+
const xsdContent = readFileSync(xsdPath, "utf-8");
|
|
1650
|
+
const schema = parseXsd(xsdContent);
|
|
1651
|
+
schema.$filename = `${schemaName}.xsd`;
|
|
1652
|
+
const basePath = dirname(xsdPath);
|
|
1653
|
+
linkSchema(schema, {
|
|
1654
|
+
basePath,
|
|
1655
|
+
throwOnMissing: false
|
|
1656
|
+
});
|
|
1657
|
+
const schemaInfo = {
|
|
1658
|
+
name: schemaName,
|
|
1659
|
+
xsdContent,
|
|
1660
|
+
schema,
|
|
1661
|
+
sourceName,
|
|
1662
|
+
xsdPath
|
|
1663
|
+
};
|
|
1664
|
+
globalAllSchemas.set(schemaName, schemaInfo);
|
|
1665
|
+
discoverReferencedSchemas(schema, xsdPath, {
|
|
1666
|
+
xsdDir: source.xsdDir,
|
|
1667
|
+
sourceName,
|
|
1668
|
+
discovered: /* @__PURE__ */ new Set(),
|
|
1669
|
+
globalAllSchemas,
|
|
1670
|
+
log
|
|
1671
|
+
});
|
|
1672
|
+
return schemaInfo;
|
|
1673
|
+
} catch (error) {
|
|
1674
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1675
|
+
log(` ❌ Failed to parse ${schemaName}: ${err.message}`);
|
|
1676
|
+
result.errors.push({
|
|
1677
|
+
schema: schemaName,
|
|
1678
|
+
source: sourceName,
|
|
1679
|
+
error: err
|
|
1680
|
+
});
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
/**
|
|
1685
|
+
* Recursively discover and parse schemas referenced via xs:include or xs:redefine.
|
|
1686
|
+
* This ensures schemas like types/devc.xsd are in globalAllSchemas when devc.xsd references them.
|
|
1687
|
+
*
|
|
1688
|
+
* @param schema - The parsed schema object
|
|
1689
|
+
* @param currentXsdPath - The path of the current XSD file (for resolving relative paths)
|
|
1690
|
+
* @param discovery - Shared discovery state (source, registries, logger)
|
|
1691
|
+
*/
|
|
1692
|
+
function discoverReferencedSchemas(schema, currentXsdPath, discovery) {
|
|
1693
|
+
const { discovered, globalAllSchemas, log } = discovery;
|
|
1694
|
+
const includes = schema.include;
|
|
1695
|
+
const redefines = schema.redefine;
|
|
1696
|
+
const refs = [...includes ?? [], ...redefines ?? []];
|
|
1697
|
+
for (const ref of refs) {
|
|
1698
|
+
if (!ref.schemaLocation) continue;
|
|
1699
|
+
const schemaNameWithPath = ref.schemaLocation.replace(/\.xsd$/, "");
|
|
1700
|
+
if (discovered.has(schemaNameWithPath) || globalAllSchemas.has(schemaNameWithPath)) continue;
|
|
1701
|
+
discovered.add(schemaNameWithPath);
|
|
1702
|
+
const currentXsdDir = dirname(currentXsdPath);
|
|
1703
|
+
const refXsdPath = join(currentXsdDir, ref.schemaLocation);
|
|
1704
|
+
if (!existsSync(refXsdPath)) {
|
|
1705
|
+
log(` ⚠️ Referenced schema not found: ${ref.schemaLocation} (resolved from ${currentXsdDir})`);
|
|
1706
|
+
continue;
|
|
1707
|
+
}
|
|
1708
|
+
loadReferencedSchema(ref.schemaLocation, refXsdPath, schemaNameWithPath, discovery);
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
/**
|
|
1712
|
+
* Parse one referenced schema, register it in the global map,
|
|
1713
|
+
* and recurse into the schemas it references.
|
|
1714
|
+
*/
|
|
1715
|
+
function loadReferencedSchema(schemaLocation, refXsdPath, schemaNameWithPath, discovery) {
|
|
1716
|
+
const { sourceName, globalAllSchemas, log } = discovery;
|
|
1717
|
+
try {
|
|
1718
|
+
const refXsdContent = readFileSync(refXsdPath, "utf-8");
|
|
1719
|
+
const refSchema = parseXsd(refXsdContent);
|
|
1720
|
+
refSchema.$filename = schemaLocation;
|
|
1721
|
+
const refSchemaInfo = {
|
|
1722
|
+
name: schemaNameWithPath,
|
|
1723
|
+
xsdContent: refXsdContent,
|
|
1724
|
+
schema: refSchema,
|
|
1725
|
+
sourceName,
|
|
1726
|
+
xsdPath: refXsdPath
|
|
1727
|
+
};
|
|
1728
|
+
globalAllSchemas.set(schemaNameWithPath, refSchemaInfo);
|
|
1729
|
+
log(` 📎 Auto-discovered: ${schemaNameWithPath}`);
|
|
1730
|
+
discoverReferencedSchemas(refSchema, refXsdPath, discovery);
|
|
1731
|
+
} catch (error) {
|
|
1732
|
+
log(` ⚠️ Failed to parse referenced schema ${schemaLocation}: ${(error instanceof Error ? error : new Error(String(error))).message}`);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
/** Second pass: run transforms with the global schema map. */
|
|
1736
|
+
async function runTransforms(ctx) {
|
|
1737
|
+
const { config, sources, processedSchemas, globalAllSchemas, rootDir, dryRun, result, log } = ctx;
|
|
1659
1738
|
for (const [sourceName, source] of Object.entries(sources)) {
|
|
1660
1739
|
const schemaInfos = processedSchemas.get(sourceName) ?? [];
|
|
1661
|
-
for (const schemaInfo of schemaInfos) {
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
}
|
|
1684
|
-
} catch (error) {
|
|
1685
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1686
|
-
log(` ❌ [${generator.name}] Failed ${schemaInfo.name}: ${err.message}`);
|
|
1687
|
-
result.errors.push({
|
|
1688
|
-
schema: schemaInfo.name,
|
|
1689
|
-
source: sourceName,
|
|
1690
|
-
error: err
|
|
1691
|
-
});
|
|
1740
|
+
for (const schemaInfo of schemaInfos) await runTransformPhase(config, {
|
|
1741
|
+
schema: schemaInfo,
|
|
1742
|
+
source,
|
|
1743
|
+
allSchemas: globalAllSchemas,
|
|
1744
|
+
allSources: sources,
|
|
1745
|
+
rootDir,
|
|
1746
|
+
resolveImport: createImportResolver(schemaInfo, source, sources, config)
|
|
1747
|
+
}, source, sourceName, dryRun, result, log);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
/** Run the transform of every generator for one schema and write the files. */
|
|
1751
|
+
async function runTransformPhase(config, transformCtx, source, sourceName, dryRun, result, log) {
|
|
1752
|
+
for (const generator of config.generators) {
|
|
1753
|
+
if (!generator.transform) continue;
|
|
1754
|
+
try {
|
|
1755
|
+
const files = await generator.transform(transformCtx);
|
|
1756
|
+
for (const file of files) {
|
|
1757
|
+
const fullPath = join(source.outputDir, file.path);
|
|
1758
|
+
writeGeneratedFile(fullPath, file.content, {
|
|
1759
|
+
path: fullPath,
|
|
1760
|
+
source: sourceName
|
|
1761
|
+
}, dryRun, result, log, ` ✅ [${generator.name}] Generated ${file.path}`);
|
|
1692
1762
|
}
|
|
1763
|
+
} catch (error) {
|
|
1764
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1765
|
+
log(` ❌ [${generator.name}] Failed ${transformCtx.schema.name}: ${err.message}`);
|
|
1766
|
+
result.errors.push({
|
|
1767
|
+
schema: transformCtx.schema.name,
|
|
1768
|
+
source: sourceName,
|
|
1769
|
+
error: err
|
|
1770
|
+
});
|
|
1693
1771
|
}
|
|
1694
1772
|
}
|
|
1773
|
+
}
|
|
1774
|
+
/** Run finalize for all generators. */
|
|
1775
|
+
async function runFinalize(config, sources, processedSchemas, rootDir, dryRun, result, log) {
|
|
1695
1776
|
const finalizeCtx = {
|
|
1696
1777
|
processedSchemas,
|
|
1697
1778
|
sources,
|
|
1698
1779
|
rootDir
|
|
1699
1780
|
};
|
|
1700
|
-
for (const generator of config.generators)
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
const
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
}
|
|
1709
|
-
result.
|
|
1710
|
-
path: fullPath,
|
|
1711
|
-
source: sourceName
|
|
1712
|
-
});
|
|
1713
|
-
log(` ✅ [${generator.name}] Generated ${file.path} for ${sourceName}`);
|
|
1781
|
+
for (const generator of config.generators) {
|
|
1782
|
+
if (!generator.finalize) continue;
|
|
1783
|
+
try {
|
|
1784
|
+
log(`\n[${generator.name}] Running finalize...`);
|
|
1785
|
+
const files = await generator.finalize(finalizeCtx);
|
|
1786
|
+
for (const file of files) writeFinalizeFiles(file, sources, generator.name, dryRun, result, log);
|
|
1787
|
+
} catch (error) {
|
|
1788
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1789
|
+
log(` ❌ [${generator.name}] Finalize failed: ${err.message}`);
|
|
1790
|
+
result.errors.push({ error: err });
|
|
1714
1791
|
}
|
|
1715
|
-
} catch (error) {
|
|
1716
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
1717
|
-
log(` ❌ [${generator.name}] Finalize failed: ${err.message}`);
|
|
1718
|
-
result.errors.push({ error: err });
|
|
1719
1792
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1793
|
+
}
|
|
1794
|
+
/** Write one finalize file into every source's output dir. */
|
|
1795
|
+
function writeFinalizeFiles(file, sources, generatorName, dryRun, result, log) {
|
|
1796
|
+
for (const [sourceName, source] of Object.entries(sources)) {
|
|
1797
|
+
const fullPath = join(source.outputDir, file.path);
|
|
1798
|
+
writeGeneratedFile(fullPath, file.content, {
|
|
1799
|
+
path: fullPath,
|
|
1800
|
+
source: sourceName
|
|
1801
|
+
}, dryRun, result, log, ` ✅ [${generatorName}] Generated ${file.path} for ${sourceName}`);
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
/** Run the afterAll hook and write any extra files it produces. */
|
|
1805
|
+
async function runAfterAll(config, sources, processedSchemas, rootDir, dryRun, result, log) {
|
|
1806
|
+
if (!config.afterAll) return;
|
|
1807
|
+
log(`\n🔧 Running afterAll hook...`);
|
|
1808
|
+
const afterAllCtx = {
|
|
1809
|
+
sources,
|
|
1810
|
+
rootDir,
|
|
1811
|
+
processedSchemas,
|
|
1812
|
+
generatedFiles: result.files.map((f) => ({
|
|
1813
|
+
path: f.path,
|
|
1814
|
+
content: ""
|
|
1815
|
+
}))
|
|
1816
|
+
};
|
|
1817
|
+
const extraFiles = await config.afterAll(afterAllCtx);
|
|
1818
|
+
if (!extraFiles || !Array.isArray(extraFiles)) return;
|
|
1819
|
+
for (const file of extraFiles) {
|
|
1820
|
+
const fullPath = join(rootDir, file.path);
|
|
1821
|
+
writeGeneratedFile(fullPath, file.content, {
|
|
1822
|
+
path: fullPath,
|
|
1823
|
+
source: "afterAll"
|
|
1824
|
+
}, dryRun, result, log, ` ✅ [afterAll] Generated ${file.path}`);
|
|
1744
1825
|
}
|
|
1745
|
-
|
|
1826
|
+
}
|
|
1827
|
+
/** Write one generated file (skipped in dry run) and record it. */
|
|
1828
|
+
function writeGeneratedFile(fullPath, content, record, dryRun, result, log, logMessage) {
|
|
1829
|
+
if (!dryRun) {
|
|
1830
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
1831
|
+
writeFileSync(fullPath, content);
|
|
1832
|
+
}
|
|
1833
|
+
result.files.push(record);
|
|
1834
|
+
log(logMessage);
|
|
1746
1835
|
}
|
|
1747
1836
|
function createImportResolver(currentSchema, currentSource, allSources, config) {
|
|
1748
1837
|
const ext = config.importExtension ?? "";
|
|
1749
1838
|
return (schemaLocation) => {
|
|
1750
1839
|
const schemaPath = schemaLocation.replace(/\.xsd$/, "");
|
|
1751
1840
|
const schemaBaseName = schemaPath.replace(/^.*\//, "");
|
|
1752
|
-
const
|
|
1753
|
-
const
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
return acc;
|
|
1757
|
-
}, []).join("/");
|
|
1758
|
-
if (currentSource.schemas.includes(normalizedPath)) {
|
|
1759
|
-
const fromDir = dirname(currentSchema.name);
|
|
1760
|
-
const toPath = normalizedPath;
|
|
1761
|
-
const relImport = fromDir === dirname(toPath) ? `./${basename(toPath)}${ext}` : relative(fromDir || ".", toPath).replaceAll(/\\/g, "/") || `./${basename(toPath)}`;
|
|
1762
|
-
return relImport.startsWith(".") ? `${relImport}${ext}` : `./${relImport}${ext}`;
|
|
1763
|
-
}
|
|
1764
|
-
if (currentSource.schemas.includes(schemaPath)) return `./${schemaPath}${ext}`;
|
|
1765
|
-
if (currentSource.schemas.includes(schemaBaseName)) return `./${schemaBaseName}${ext}`;
|
|
1766
|
-
for (const [sourceName, source] of Object.entries(allSources)) {
|
|
1767
|
-
if (sourceName === currentSource.name) continue;
|
|
1768
|
-
if (source.schemas.includes(normalizedPath)) return `${relative(currentSource.outputDir, source.outputDir)}/${normalizedPath}${ext}`.replaceAll(/\\/g, "/");
|
|
1769
|
-
if (source.schemas.includes(schemaPath)) return `${relative(currentSource.outputDir, source.outputDir)}/${schemaPath}${ext}`.replaceAll(/\\/g, "/");
|
|
1770
|
-
if (source.schemas.includes(schemaBaseName)) return `${relative(currentSource.outputDir, source.outputDir)}/${schemaBaseName}${ext}`.replaceAll(/\\/g, "/");
|
|
1771
|
-
}
|
|
1772
|
-
return null;
|
|
1841
|
+
const normalizedPath = normalizeSchemaPath(currentSchema.name, schemaPath);
|
|
1842
|
+
const relImport = resolveInCurrentSource(currentSchema.name, currentSource, normalizedPath, schemaPath, schemaBaseName, ext);
|
|
1843
|
+
if (relImport) return relImport;
|
|
1844
|
+
return resolveInOtherSources(currentSource, allSources, normalizedPath, schemaPath, schemaBaseName, ext);
|
|
1773
1845
|
};
|
|
1774
1846
|
}
|
|
1775
1847
|
/**
|
|
1848
|
+
* Resolve the schemaLocation relative to the current schema's directory
|
|
1849
|
+
* and normalize the path (handle ../ etc.).
|
|
1850
|
+
* e.g., if current is "sap/classes" and schemaLocation is "adtcore.xsd" -> "sap/adtcore"
|
|
1851
|
+
* e.g., if current is "custom/discovery" and schemaLocation is "../sap/atom.xsd" -> "sap/atom"
|
|
1852
|
+
*/
|
|
1853
|
+
function normalizeSchemaPath(currentSchemaName, schemaPath) {
|
|
1854
|
+
const currentSchemaDir = dirname(currentSchemaName);
|
|
1855
|
+
return (currentSchemaDir !== "." ? join(currentSchemaDir, schemaPath).replaceAll("\\", "/") : schemaPath).split("/").reduce((acc, part) => {
|
|
1856
|
+
if (part === "..") acc.pop();
|
|
1857
|
+
else if (part !== ".") acc.push(part);
|
|
1858
|
+
return acc;
|
|
1859
|
+
}, []).join("/");
|
|
1860
|
+
}
|
|
1861
|
+
/**
|
|
1862
|
+
* Calculate the import path when the target schema is in the current source.
|
|
1863
|
+
*/
|
|
1864
|
+
function resolveInCurrentSource(currentSchemaName, currentSource, normalizedPath, schemaPath, schemaBaseName, ext) {
|
|
1865
|
+
if (currentSource.schemas.includes(normalizedPath)) {
|
|
1866
|
+
const fromDir = dirname(currentSchemaName);
|
|
1867
|
+
const toPath = normalizedPath;
|
|
1868
|
+
const relImport = fromDir === dirname(toPath) ? `./${basename(toPath)}${ext}` : relative(fromDir || ".", toPath).replaceAll("\\", "/") || `./${basename(toPath)}`;
|
|
1869
|
+
return relImport.startsWith(".") ? `${relImport}${ext}` : `./${relImport}${ext}`;
|
|
1870
|
+
}
|
|
1871
|
+
if (currentSource.schemas.includes(schemaPath)) return `./${schemaPath}${ext}`;
|
|
1872
|
+
if (currentSource.schemas.includes(schemaBaseName)) return `./${schemaBaseName}${ext}`;
|
|
1873
|
+
return null;
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Check other sources for the target schema.
|
|
1877
|
+
*/
|
|
1878
|
+
function resolveInOtherSources(currentSource, allSources, normalizedPath, schemaPath, schemaBaseName, ext) {
|
|
1879
|
+
for (const [sourceName, source] of Object.entries(allSources)) {
|
|
1880
|
+
if (sourceName === currentSource.name) continue;
|
|
1881
|
+
for (const candidate of [
|
|
1882
|
+
normalizedPath,
|
|
1883
|
+
schemaPath,
|
|
1884
|
+
schemaBaseName
|
|
1885
|
+
]) if (source.schemas.includes(candidate)) return `${relative(currentSource.outputDir, source.outputDir)}/${candidate}${ext}`.replaceAll("\\", "/");
|
|
1886
|
+
}
|
|
1887
|
+
return null;
|
|
1888
|
+
}
|
|
1889
|
+
/**
|
|
1776
1890
|
* Discover all dependent schemas by recursively parsing XSD files
|
|
1777
1891
|
* and extracting schemaLocation from xs:import, xs:include, xs:redefine
|
|
1778
1892
|
*/
|
|
@@ -1805,30 +1919,21 @@ function discoverDependentSchemas(entrySchemas, xsdDir, log) {
|
|
|
1805
1919
|
function extractSchemaLocations(schema, xsdDir, currentSchema) {
|
|
1806
1920
|
const locations = [];
|
|
1807
1921
|
const currentDir = dirname(join(xsdDir, `${currentSchema}.xsd`));
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
const name = resolveSchemaName(imp.schemaLocation, currentDir, xsdDir);
|
|
1812
|
-
if (name) locations.push(name);
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1815
|
-
const includes = schema.include;
|
|
1816
|
-
if (includes) {
|
|
1817
|
-
for (const inc of includes) if (inc.schemaLocation) {
|
|
1818
|
-
const name = resolveSchemaName(inc.schemaLocation, currentDir, xsdDir);
|
|
1819
|
-
if (name) locations.push(name);
|
|
1820
|
-
}
|
|
1821
|
-
}
|
|
1822
|
-
const redefines = schema.redefine;
|
|
1823
|
-
if (redefines) {
|
|
1824
|
-
for (const red of redefines) if (red.schemaLocation) {
|
|
1825
|
-
const name = resolveSchemaName(red.schemaLocation, currentDir, xsdDir);
|
|
1826
|
-
if (name) locations.push(name);
|
|
1827
|
-
}
|
|
1828
|
-
}
|
|
1922
|
+
collectSchemaLocations(schema.import, currentDir, xsdDir, locations);
|
|
1923
|
+
collectSchemaLocations(schema.include, currentDir, xsdDir, locations);
|
|
1924
|
+
collectSchemaLocations(schema.redefine, currentDir, xsdDir, locations);
|
|
1829
1925
|
return locations;
|
|
1830
1926
|
}
|
|
1831
1927
|
/**
|
|
1928
|
+
* Resolve the schema names of schemaLocation entries and append them.
|
|
1929
|
+
*/
|
|
1930
|
+
function collectSchemaLocations(refs, currentDir, xsdDir, locations) {
|
|
1931
|
+
for (const ref of refs ?? []) if (ref.schemaLocation) {
|
|
1932
|
+
const name = resolveSchemaName(ref.schemaLocation, currentDir, xsdDir);
|
|
1933
|
+
if (name) locations.push(name);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
/**
|
|
1832
1937
|
* Resolve schemaLocation to a schema name relative to xsdDir
|
|
1833
1938
|
*/
|
|
1834
1939
|
function resolveSchemaName(schemaLocation, currentDir, xsdDir) {
|
|
@@ -1839,4 +1944,4 @@ function resolveSchemaName(schemaLocation, currentDir, xsdDir) {
|
|
|
1839
1944
|
}
|
|
1840
1945
|
|
|
1841
1946
|
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 };
|
|
1842
|
-
//# sourceMappingURL=runner-
|
|
1947
|
+
//# sourceMappingURL=runner-BZNOc_YZ.mjs.map
|