@hla4ts/fom-codegen 0.1.0

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,452 @@
1
+ /**
2
+ * XSD to TypeScript Type Generator
3
+ *
4
+ * Generates TypeScript type definitions from parsed XSD schemas.
5
+ */
6
+
7
+ import type { XsdSchema, XsdType, XsdElement } from "./xsd-parser.ts";
8
+
9
+ export interface TypeGenerationOptions {
10
+ outputFile?: string;
11
+ format?: "omt" | "fdd" | "dif";
12
+ includeDocumentation?: boolean;
13
+ }
14
+
15
+ /**
16
+ * Generate TypeScript types from an XSD schema.
17
+ */
18
+ export function generateTypesFromXsd(
19
+ schema: XsdSchema,
20
+ options: TypeGenerationOptions = {}
21
+ ): string {
22
+ const { includeDocumentation = true } = options;
23
+ const lines: string[] = [];
24
+
25
+ // Header
26
+ lines.push("/**");
27
+ lines.push(" * Generated TypeScript types from IEEE 1516-2025 XSD Schema");
28
+ lines.push(" *");
29
+ lines.push(" * This file is auto-generated. Do not edit manually.");
30
+ lines.push(" * Regenerate with: bun run scripts/generate-types.ts");
31
+ lines.push(" */");
32
+ lines.push("");
33
+ lines.push("// ============================================================================");
34
+ lines.push("// Enumerations");
35
+ lines.push("// ============================================================================");
36
+ lines.push("");
37
+
38
+ // Generate enumerations first
39
+ for (const [typeName, type] of schema.types.entries()) {
40
+ if (type.kind === "enum" && type.enumValues) {
41
+ generateEnum(lines, typeName, type, includeDocumentation);
42
+ }
43
+ }
44
+
45
+ lines.push("");
46
+ lines.push("// ============================================================================");
47
+ lines.push("// Complex Types");
48
+ lines.push("// ============================================================================");
49
+ lines.push("");
50
+
51
+ // Generate complex types (track generated to avoid duplicates)
52
+ const generatedInterfaces = new Set<string>();
53
+ for (const [typeName, type] of schema.types.entries()) {
54
+ if (type.kind === "complex") {
55
+ const interfaceName = sanitizeTypeName(typeName);
56
+ if (!generatedInterfaces.has(interfaceName)) {
57
+ generatedInterfaces.add(interfaceName);
58
+ generateInterface(lines, typeName, type, schema, includeDocumentation);
59
+ }
60
+ }
61
+ }
62
+
63
+ // Generate root element type if exists
64
+ if (schema.rootElement) {
65
+ const rootElement = schema.elements.get(schema.rootElement);
66
+ if (rootElement) {
67
+ const rootTypeName = resolveTypeName(rootElement.type);
68
+ const sanitizedRootTypeName = sanitizeTypeName(rootTypeName);
69
+ lines.push("");
70
+ lines.push("// ============================================================================");
71
+ lines.push("// Root Element");
72
+ lines.push("// ============================================================================");
73
+ lines.push("");
74
+ lines.push(`export type ${capitalize(schema.rootElement)}Type = ${sanitizedRootTypeName};`);
75
+ }
76
+ }
77
+
78
+ return lines.join("\n");
79
+ }
80
+
81
+ function generateEnum(
82
+ lines: string[],
83
+ typeName: string,
84
+ type: XsdType,
85
+ includeDocumentation: boolean
86
+ ): void {
87
+ if (!type.enumValues || type.enumValues.length === 0) return;
88
+
89
+ if (includeDocumentation && type.documentation) {
90
+ lines.push("/**");
91
+ lines.push(` * ${type.documentation}`);
92
+ lines.push(" */");
93
+ }
94
+
95
+ const enumName = sanitizeTypeName(typeName);
96
+ const values = type.enumValues.map((v) => `"${v}"`).join(" | ");
97
+ lines.push(`export type ${enumName} = ${values};`);
98
+ lines.push("");
99
+ }
100
+
101
+ function generateInterface(
102
+ lines: string[],
103
+ typeName: string,
104
+ type: XsdType,
105
+ schema: XsdSchema,
106
+ includeDocumentation: boolean
107
+ ): void {
108
+ if (includeDocumentation && type.documentation) {
109
+ lines.push("/**");
110
+ lines.push(` * ${type.documentation}`);
111
+ lines.push(" */");
112
+ }
113
+
114
+ const interfaceName = sanitizeTypeName(typeName);
115
+ // Track property names to avoid duplicates
116
+ const seenProperties = new Set<string>();
117
+
118
+ lines.push(`export interface ${interfaceName} {`);
119
+
120
+ // Handle base type (inheritance)
121
+ if (type.baseType) {
122
+ const baseTypeName = resolveTypeName(type.baseType);
123
+ lines.push(` // Extends ${baseTypeName}`);
124
+ }
125
+
126
+ // Generate properties from elements (skip elements without names)
127
+ for (const element of type.elements) {
128
+ if (element.name && element.name.trim() !== "") {
129
+ // Skip if we've already seen this property name
130
+ if (!seenProperties.has(element.name)) {
131
+ seenProperties.add(element.name);
132
+ generateProperty(lines, element, schema, includeDocumentation);
133
+ }
134
+ }
135
+ }
136
+
137
+ // Generate properties from attributes (skip attributes without names)
138
+ for (const attr of type.attributes) {
139
+ if (attr.name && attr.name.trim() !== "") {
140
+ // Skip if we've already seen this property name
141
+ if (!seenProperties.has(attr.name)) {
142
+ seenProperties.add(attr.name);
143
+ generateAttributeProperty(lines, attr, schema);
144
+ }
145
+ }
146
+ }
147
+
148
+ lines.push("}");
149
+ lines.push("");
150
+ }
151
+
152
+ function generateProperty(
153
+ lines: string[],
154
+ element: XsdElement,
155
+ schema: XsdSchema,
156
+ includeDocumentation: boolean
157
+ ): void {
158
+ if (includeDocumentation && element.documentation) {
159
+ lines.push(` /**`);
160
+ lines.push(` * ${element.documentation}`);
161
+ lines.push(` */`);
162
+ }
163
+
164
+ const propName = element.name;
165
+ const typeName = resolveTypeName(element.type, schema);
166
+ let tsType = mapXsdTypeToTs(typeName, schema, element.name);
167
+
168
+ // Fallback for empty or unresolved types
169
+ if (!tsType || tsType.trim() === "") {
170
+ tsType = "unknown";
171
+ }
172
+
173
+ let propertyType = tsType;
174
+ if (element.array) {
175
+ propertyType = `${tsType}[]`;
176
+ }
177
+
178
+ const optional = element.optional ? "?" : "";
179
+ lines.push(` ${propName}${optional}: ${propertyType};`);
180
+ }
181
+
182
+ function generateAttributeProperty(
183
+ lines: string[],
184
+ attr: { name: string; type: string; required: boolean },
185
+ schema: XsdSchema
186
+ ): void {
187
+ const propName = attr.name;
188
+ const typeName = resolveTypeName(attr.type, schema);
189
+ let tsType = mapXsdTypeToTs(typeName, schema);
190
+
191
+ // Fallback for empty or unresolved types
192
+ if (!tsType || tsType.trim() === "") {
193
+ tsType = "unknown";
194
+ }
195
+
196
+ const optional = attr.required ? "" : "?";
197
+ lines.push(` ${propName}${optional}: ${tsType};`);
198
+ }
199
+
200
+ function resolveTypeName(typeRef: string, schema?: XsdSchema): string {
201
+ // Remove namespace prefix (e.g., "xs:string" -> "string")
202
+ const parts = typeRef.split(":");
203
+ const localName = parts[parts.length - 1];
204
+
205
+ // Map XSD built-in types
206
+ const builtInTypes: Record<string, string> = {
207
+ string: "string",
208
+ int: "number",
209
+ integer: "number",
210
+ long: "number",
211
+ short: "number",
212
+ byte: "number",
213
+ decimal: "number",
214
+ float: "number",
215
+ double: "number",
216
+ boolean: "boolean",
217
+ date: "string", // ISO date string
218
+ dateTime: "string", // ISO datetime string
219
+ time: "string",
220
+ duration: "string",
221
+ anyURI: "string",
222
+ ID: "string",
223
+ IDREF: "string",
224
+ NCName: "string",
225
+ base64Binary: "string",
226
+ anyType: "unknown",
227
+ positiveInteger: "number", // XSD positiveInteger maps to number
228
+ };
229
+
230
+ if (builtInTypes[localName]) {
231
+ return builtInTypes[localName];
232
+ }
233
+
234
+ // Check if it's a type defined in the schema
235
+ if (schema && schema.types.has(localName)) {
236
+ const type = schema.types.get(localName)!;
237
+
238
+ // If it's an enum, return the enum type name
239
+ if (type.kind === "enum") {
240
+ return sanitizeTypeName(localName);
241
+ }
242
+
243
+ // If it's a simple type with a base type, resolve the base type
244
+ if (type.kind === "simple" && type.baseType) {
245
+ return resolveTypeName(type.baseType, schema);
246
+ }
247
+
248
+ // If it's a complex type with simpleContent, resolve the base type recursively
249
+ if (type.kind === "complex" && type.baseType) {
250
+ const baseResolved = resolveTypeName(type.baseType, schema);
251
+ // If base resolves to a primitive, return it
252
+ if (builtInTypes[baseResolved] || ["string", "number", "boolean"].includes(baseResolved)) {
253
+ return baseResolved;
254
+ }
255
+ // If base resolves to an enum, return the enum name (not the complex type wrapper)
256
+ const baseType = schema.types.get(baseResolved);
257
+ if (baseType && baseType.kind === "enum") {
258
+ return sanitizeTypeName(baseResolved);
259
+ }
260
+ // Otherwise, continue resolving
261
+ return baseResolved;
262
+ }
263
+
264
+ return sanitizeTypeName(localName);
265
+ }
266
+
267
+ // Default: return as-is (will be sanitized later)
268
+ return localName;
269
+ }
270
+
271
+ function mapXsdTypeToTs(typeName: string, schema: XsdSchema, elementName?: string): string {
272
+ const resolved = resolveTypeName(typeName, schema);
273
+
274
+ // If it's a primitive, return it
275
+ if (
276
+ ["string", "number", "boolean", "unknown"].includes(resolved)
277
+ ) {
278
+ return resolved;
279
+ }
280
+
281
+ // Get the type from schema - try both with and without "Type" suffix
282
+ let type = schema.types.get(resolved);
283
+ let typeKey = resolved;
284
+
285
+ // If not found, try with "Type" suffix
286
+ if (!type && !resolved.endsWith("Type")) {
287
+ const withType = resolved + "Type";
288
+ type = schema.types.get(withType);
289
+ if (type) {
290
+ typeKey = withType;
291
+ }
292
+ }
293
+
294
+ // Check if it's an enum type
295
+ if (type && type.kind === "enum") {
296
+ return sanitizeTypeName(typeKey);
297
+ }
298
+
299
+ // Check if it's a complex type with simpleContent (like String, Model, etc.)
300
+ // These should resolve to their base type
301
+ if (type && type.kind === "complex" && type.baseType) {
302
+ const baseResolved = resolveTypeName(type.baseType, schema);
303
+ // If base resolves to a primitive, use that
304
+ if (["string", "number", "boolean"].includes(baseResolved)) {
305
+ return baseResolved;
306
+ }
307
+ // Check if base type is an enum - this is the key case for Model -> OMTypeEnumeration
308
+ const baseType = schema.types.get(baseResolved);
309
+ if (baseType && baseType.kind === "enum") {
310
+ return sanitizeTypeName(baseResolved);
311
+ }
312
+ // Check if base type is a union - resolve to first member if it's an enum
313
+ if (baseType && baseType.kind === "simple" && baseType.baseType) {
314
+ const firstMember = resolveTypeName(baseType.baseType, schema);
315
+ const firstMemberType = schema.types.get(firstMember);
316
+ if (firstMemberType && firstMemberType.kind === "enum") {
317
+ return sanitizeTypeName(firstMember);
318
+ }
319
+ // If union member resolves to string, use string (union of enum + string)
320
+ if (firstMember === "string") {
321
+ return "string";
322
+ }
323
+ }
324
+ // Check if base type name suggests it's an enum (fallback)
325
+ if (baseResolved.endsWith("Enumeration")) {
326
+ const enumType = schema.types.get(baseResolved);
327
+ if (enumType && enumType.kind === "enum") {
328
+ return sanitizeTypeName(baseResolved);
329
+ }
330
+ }
331
+ // If we can't resolve further, return the complex type name
332
+ // (This handles cases where simpleContent extends a complex type)
333
+ }
334
+
335
+ // Check if it's a simple type with a base type
336
+ if (type && type.kind === "simple" && type.baseType) {
337
+ const baseResolved = resolveTypeName(type.baseType, schema);
338
+ if (["string", "number", "boolean"].includes(baseResolved)) {
339
+ return baseResolved;
340
+ }
341
+ // Check if base is an enum
342
+ const baseType = schema.types.get(baseResolved);
343
+ if (baseType && baseType.kind === "enum") {
344
+ return sanitizeTypeName(baseResolved);
345
+ }
346
+ // Pattern types (dimensionValuePattern, cardinalityPattern) are string-based
347
+ // and should resolve to string
348
+ if (baseResolved === "string") {
349
+ return "string";
350
+ }
351
+ }
352
+
353
+ // Fallback: if type name suggests a pattern type or unknown simple type, default to string
354
+ if (!type && (resolved.includes("Pattern") || resolved.includes("Enumeration"))) {
355
+ // Try to find it in schema as a simple type
356
+ const simpleType = schema.types.get(resolved);
357
+ if (simpleType && simpleType.kind === "simple" && simpleType.baseType) {
358
+ const baseResolved = resolveTypeName(simpleType.baseType, schema);
359
+ if (baseResolved === "string") {
360
+ return "string";
361
+ }
362
+ }
363
+ // If it's an enumeration that wasn't found, it might be a pattern-based enum
364
+ // Default to string for pattern-based types
365
+ if (resolved.includes("Pattern")) {
366
+ return "string";
367
+ }
368
+ }
369
+
370
+ // Otherwise, it's a complex type - return the interface name
371
+ // The generated interface name is sanitizeTypeName(typeKey)
372
+ // sanitizeTypeName removes "Type" suffix once
373
+ // So if typeKey is "ChangeDefaultAttributeTransportationTypeType", sanitize produces "ChangeDefaultAttributeTransportationType"
374
+ const sanitized = sanitizeTypeName(typeKey);
375
+
376
+ // Special case: if the element name (from XSD) ends with "Type", and we created an inline type,
377
+ // the parser would have created a type with double "Type" (elementName + "Type"),
378
+ // and sanitizeTypeName removes one, leaving us with the correct name.
379
+ // But when we reference it, if the original typeName (from element.type) was the element name itself,
380
+ // we need to ensure we use the correct generated interface name.
381
+
382
+ // If elementName is provided and ends with "Type", and typeKey also ends with "Type",
383
+ // then the generated interface name should keep the "Type" suffix
384
+ if (elementName && elementName.endsWith("Type") && typeKey.endsWith("Type") && type) {
385
+ // The element name ends with "Type", so the parser created a type with double "Type"
386
+ // sanitizeTypeName removes one, so we get the correct name with one "Type"
387
+ return sanitized;
388
+ }
389
+
390
+ // If typeKey ends with "Type" and we found a type, the generated interface name
391
+ // is sanitized (which removes "Type"), but we might need to add it back if the
392
+ // original XSD type name had it and the parser created it with double "Type"
393
+ // Actually, let's check: if we found the type with "Type" suffix, and sanitize removes it,
394
+ // but the actual generated interface might have "Type" if the parser created it with double "Type"
395
+
396
+ // The safest approach: check what the actual generated interface name would be
397
+ // by looking at what sanitizeTypeName produces for the typeKey
398
+ // If typeKey is "changeDefaultAttributeTransportationTypeType" (from parser),
399
+ // sanitizeTypeName produces "changeDefaultAttributeTransportationType" (removes one "Type")
400
+ // But wait, sanitizeTypeName also capitalizes, so it would be "ChangeDefaultAttributeTransportationType"
401
+
402
+ // Actually, the issue is simpler: when an element name ends with "Type" (like "changeDefaultAttributeTransportationType"),
403
+ // the parser creates type name "ChangeDefaultAttributeTransportationTypeType" (capitalize + "Type"),
404
+ // and sanitizeTypeName("ChangeDefaultAttributeTransportationTypeType") = "ChangeDefaultAttributeTransportationType"
405
+ // So the generated interface IS "ChangeDefaultAttributeTransportationType"
406
+
407
+ // But when we reference it via element.type = "changeDefaultAttributeTransportationType",
408
+ // resolveTypeName doesn't find it (because the type key is "ChangeDefaultAttributeTransportationTypeType"),
409
+ // so it returns sanitizeTypeName("changeDefaultAttributeTransportationType") = "ChangeDefaultAttributeTransportation"
410
+ // Then mapXsdTypeToTs gets "ChangeDefaultAttributeTransportation", doesn't find it,
411
+ // tries "ChangeDefaultAttributeTransportationType", finds it, and should return "ChangeDefaultAttributeTransportationType"
412
+
413
+ // But currently it's returning sanitized = sanitizeTypeName("ChangeDefaultAttributeTransportationType")
414
+ // = "ChangeDefaultAttributeTransportation" (removes "Type")
415
+
416
+ // The fix: if we found the type with "Type" suffix (typeKey ends with "Type"),
417
+ // and sanitizeTypeName would remove it, but the actual generated interface keeps it
418
+ // (because the parser created it with double "Type"), we should return sanitized + "Type"
419
+ if (typeKey.endsWith("Type") && type && typeKey !== sanitized + "Type") {
420
+ // The typeKey had "Type", sanitize removed it, but the actual interface might have "Type"
421
+ // Check if adding "Type" back would match a generated interface
422
+ // Actually, if typeKey is "ChangeDefaultAttributeTransportationType" and we found it,
423
+ // sanitizeTypeName("ChangeDefaultAttributeTransportationType") = "ChangeDefaultAttributeTransportation"
424
+ // But the actual interface is "ChangeDefaultAttributeTransportationType"
425
+ // So we need to add "Type" back
426
+ return sanitized + "Type";
427
+ }
428
+
429
+ return sanitized;
430
+ }
431
+
432
+ function sanitizeTypeName(name: string): string {
433
+ // Remove common prefixes and capitalize
434
+ let sanitized = name
435
+ .replace(/^xs:/, "")
436
+ .replace(/Type$/, "")
437
+ .replace(/^[a-z]/, (c) => c.toUpperCase());
438
+
439
+ // Handle camelCase
440
+ sanitized = sanitized.replace(/([A-Z])/g, "$1");
441
+
442
+ // Ensure it starts with uppercase
443
+ if (sanitized[0] && sanitized[0] === sanitized[0].toLowerCase()) {
444
+ sanitized = sanitized[0].toUpperCase() + sanitized.slice(1);
445
+ }
446
+
447
+ return sanitized;
448
+ }
449
+
450
+ function capitalize(str: string): string {
451
+ return str[0].toUpperCase() + str.slice(1);
452
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * XSD Types Adapter
3
+ *
4
+ * Provides adapters to convert between XSD-generated types and FomRegistry schema types.
5
+ * This allows using XSD-generated types for autocomplete while maintaining compatibility
6
+ * with the existing FomRegistry API.
7
+ */
8
+
9
+ import type {
10
+ ModelIdentification as XsdModelIdentification,
11
+ ObjectClass as XsdObjectClass,
12
+ InteractionClass as XsdInteractionClass,
13
+ Attribute as XsdAttribute,
14
+ Parameter as XsdParameter,
15
+ SharingEnumeration,
16
+ OrderEnumeration,
17
+ UpdateEnumeration,
18
+ OwnershipEnumeration,
19
+ } from "./generated/xsd-types.ts";
20
+
21
+ import type {
22
+ ModelIdentification,
23
+ ObjectClassSchema,
24
+ InteractionClassSchema,
25
+ AttributeSchema,
26
+ ParameterSchema,
27
+ } from "./types.ts";
28
+
29
+ /**
30
+ * Convert XSD ModelIdentification to FomRegistry ModelIdentification.
31
+ * This provides autocomplete based on XSD schema.
32
+ */
33
+ export function adaptModelIdentification(
34
+ xsd: XsdModelIdentification
35
+ ): ModelIdentification {
36
+ return {
37
+ name: xsd.name ?? "",
38
+ type: (xsd.type ?? "FOM") as "FOM" | "SOM",
39
+ version: xsd.version ?? "",
40
+ modificationDate: xsd.modificationDate ?? "",
41
+ securityClassification: xsd.securityClassification ?? "",
42
+ description: xsd.description ?? "",
43
+ purpose: xsd.purpose,
44
+ applicationDomain: xsd.applicationDomain,
45
+ useLimitation: xsd.useLimitation,
46
+ keyword: xsd.keyword?.map((kw) => ({
47
+ taxonomy: kw.taxonomy,
48
+ keywordValue: kw.keywordValue ?? "",
49
+ })),
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Convert XSD ObjectClass to FomRegistry ObjectClassSchema.
55
+ * Provides autocomplete based on XSD schema.
56
+ */
57
+ export function adaptObjectClass(xsd: XsdObjectClass): ObjectClassSchema {
58
+ // XSD uses 'attribute' (singular) for the array property
59
+ const attributes = (xsd as any).attribute || (xsd as any).attributes;
60
+ return {
61
+ name: xsd.name,
62
+ parent: (xsd as any).parent,
63
+ sharing: adaptSharingType(xsd.sharing),
64
+ semantics: (xsd as any).semantics,
65
+ attributes: attributes?.map(adaptAttribute),
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Convert XSD InteractionClass to FomRegistry InteractionClassSchema.
71
+ * Provides autocomplete based on XSD schema.
72
+ */
73
+ export function adaptInteractionClass(
74
+ xsd: XsdInteractionClass
75
+ ): InteractionClassSchema {
76
+ // XSD uses 'parameter' (singular) for the array property
77
+ const parameters = (xsd as any).parameter || (xsd as any).parameters;
78
+ return {
79
+ name: xsd.name,
80
+ parent: (xsd as any).parent,
81
+ sharing: adaptSharingType(xsd.sharing),
82
+ transportation: (xsd as any).transportation,
83
+ order: adaptOrderType(xsd.order),
84
+ semantics: (xsd as any).semantics,
85
+ parameters: parameters?.map(adaptParameter),
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Convert XSD Attribute to FomRegistry AttributeSchema.
91
+ */
92
+ function adaptAttribute(xsd: XsdAttribute): AttributeSchema {
93
+ return {
94
+ name: xsd.name,
95
+ dataType: xsd.dataType ?? "",
96
+ updateType: adaptUpdateType(xsd.updateType) ?? "NA",
97
+ updateCondition: xsd.updateCondition ?? "",
98
+ ownership: adaptOwnershipType(xsd.ownership) ?? "NoTransfer",
99
+ sharing: adaptSharingType(xsd.sharing) ?? "Neither",
100
+ transportation: xsd.transportation ?? "",
101
+ order: adaptOrderType(xsd.order) ?? "Receive",
102
+ semantics: xsd.semantics,
103
+ valueRequired: xsd.valueRequired === "true",
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Convert XSD Parameter to FomRegistry ParameterSchema.
109
+ */
110
+ function adaptParameter(xsd: XsdParameter): ParameterSchema {
111
+ return {
112
+ name: xsd.name,
113
+ dataType: xsd.dataType ?? "",
114
+ semantics: xsd.semantics,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Convert XSD SharingEnumeration to FomRegistry SharingType.
120
+ */
121
+ function adaptSharingType(
122
+ sharing?: SharingEnumeration
123
+ ): "Publish" | "Subscribe" | "PublishSubscribe" | "Neither" | undefined {
124
+ if (!sharing) return undefined;
125
+ return sharing as "Publish" | "Subscribe" | "PublishSubscribe" | "Neither";
126
+ }
127
+
128
+ /**
129
+ * Convert XSD OrderEnumeration to FomRegistry OrderType.
130
+ */
131
+ function adaptOrderType(
132
+ order?: OrderEnumeration
133
+ ): "Receive" | "TimeStamp" | undefined {
134
+ if (!order) return undefined;
135
+ return order as "Receive" | "TimeStamp";
136
+ }
137
+
138
+ /**
139
+ * Convert XSD UpdateEnumeration to FomRegistry UpdateType.
140
+ */
141
+ function adaptUpdateType(
142
+ update?: UpdateEnumeration
143
+ ): "Static" | "Periodic" | "Conditional" | "NA" {
144
+ if (!update) return "NA";
145
+ return update as "Static" | "Periodic" | "Conditional" | "NA";
146
+ }
147
+
148
+ /**
149
+ * Convert XSD OwnershipEnumeration to FomRegistry OwnershipType.
150
+ */
151
+ function adaptOwnershipType(
152
+ ownership?: OwnershipEnumeration
153
+ ): "Divest" | "Acquire" | "DivestAcquire" | "NoTransfer" {
154
+ if (!ownership) return "NoTransfer";
155
+ return ownership as "Divest" | "Acquire" | "DivestAcquire" | "NoTransfer";
156
+ }
157
+
158
+ /**
159
+ * Helper type that provides autocomplete for ModelIdentification using XSD types.
160
+ * Use this when you want XSD-based autocomplete:
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * import { FomRegistry } from "@hla4ts/fom-codegen";
165
+ * import type { ModelIdentification } from "@hla4ts/fom-codegen/generated";
166
+ *
167
+ * const registry = new FomRegistry();
168
+ * const modelId: ModelIdentification = {
169
+ * name: "MyFOM",
170
+ * type: "FOM", // Autocomplete shows "FOM" | "SOM"
171
+ * version: "1.0",
172
+ * // ... other fields with autocomplete
173
+ * };
174
+ * registry.setModelIdentification(adaptModelIdentification(modelId));
175
+ * ```
176
+ */
177
+ export type { XsdModelIdentification, XsdObjectClass, XsdInteractionClass };