@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.
- package/README.md +247 -0
- package/package.json +29 -0
- package/src/cli.ts +179 -0
- package/src/generated/index.ts +25 -0
- package/src/generated/xsd-types.ts +2073 -0
- package/src/index.ts +62 -0
- package/src/registry.ts +127 -0
- package/src/ts-codegen.ts +59 -0
- package/src/types.ts +172 -0
- package/src/xml-parser.ts +359 -0
- package/src/xml-writer.ts +502 -0
- package/src/xsd-parser.ts +404 -0
- package/src/xsd-type-generator.ts +452 -0
- package/src/xsd-types-adapter.ts +177 -0
package/src/index.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hla4ts/fom-codegen
|
|
3
|
+
*
|
|
4
|
+
* TypeScript-first registry and XML generator for IEEE 1516-2025 FOM/SOM.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
type SharingType,
|
|
9
|
+
type OrderType,
|
|
10
|
+
type UpdateType,
|
|
11
|
+
type OwnershipType,
|
|
12
|
+
type ModelIdentification,
|
|
13
|
+
type TimeDefinition,
|
|
14
|
+
type AttributeSchema,
|
|
15
|
+
type ObjectClassSchema,
|
|
16
|
+
type ParameterSchema,
|
|
17
|
+
type InteractionClassSchema,
|
|
18
|
+
type DimensionSchema,
|
|
19
|
+
type TransportationSchema,
|
|
20
|
+
type SwitchesSchema,
|
|
21
|
+
type SimpleDataTypeSchema,
|
|
22
|
+
type EnumeratedDataTypeSchema,
|
|
23
|
+
type ArrayDataTypeSchema,
|
|
24
|
+
type FixedRecordDataTypeSchema,
|
|
25
|
+
type VariantRecordDataTypeSchema,
|
|
26
|
+
type DataTypeSchema,
|
|
27
|
+
type FomModel,
|
|
28
|
+
type FomOutputFormat,
|
|
29
|
+
type FomOutputOptions,
|
|
30
|
+
} from "./types.ts";
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
FomRegistry,
|
|
34
|
+
defaultRegistry,
|
|
35
|
+
defineObjectClass,
|
|
36
|
+
defineInteractionClass,
|
|
37
|
+
} from "./registry.ts";
|
|
38
|
+
|
|
39
|
+
export { renderFomXml } from "./xml-writer.ts";
|
|
40
|
+
export { parseFomXml } from "./xml-parser.ts";
|
|
41
|
+
export {
|
|
42
|
+
generateFomTypescript,
|
|
43
|
+
type TsCodegenMode,
|
|
44
|
+
type TsCodegenOptions,
|
|
45
|
+
} from "./ts-codegen.ts";
|
|
46
|
+
|
|
47
|
+
// =============================================================================
|
|
48
|
+
// Generated XSD Types (for autocomplete and type checking)
|
|
49
|
+
// =============================================================================
|
|
50
|
+
export * from "./generated/index.ts";
|
|
51
|
+
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// XSD Type Adapters (convert XSD types to FomRegistry types)
|
|
54
|
+
// =============================================================================
|
|
55
|
+
export {
|
|
56
|
+
adaptModelIdentification,
|
|
57
|
+
adaptObjectClass,
|
|
58
|
+
adaptInteractionClass,
|
|
59
|
+
type XsdModelIdentification,
|
|
60
|
+
type XsdObjectClass,
|
|
61
|
+
type XsdInteractionClass,
|
|
62
|
+
} from "./xsd-types-adapter.ts";
|
package/src/registry.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
DataTypeSchema,
|
|
3
|
+
DimensionSchema,
|
|
4
|
+
FomModel,
|
|
5
|
+
FomOutputOptions,
|
|
6
|
+
InteractionClassSchema,
|
|
7
|
+
ModelIdentification,
|
|
8
|
+
ObjectClassSchema,
|
|
9
|
+
TransportationSchema,
|
|
10
|
+
TimeDefinition,
|
|
11
|
+
} from "./types.ts";
|
|
12
|
+
import { renderFomXml } from "./xml-writer.ts";
|
|
13
|
+
|
|
14
|
+
const NCNAME_PATTERN = /^[A-Za-z_][A-Za-z0-9._-]*$/;
|
|
15
|
+
|
|
16
|
+
export class FomRegistry {
|
|
17
|
+
private _modelIdentification?: ModelIdentification;
|
|
18
|
+
private _time?: TimeDefinition;
|
|
19
|
+
private readonly _objectClasses: ObjectClassSchema[] = [];
|
|
20
|
+
private readonly _interactionClasses: InteractionClassSchema[] = [];
|
|
21
|
+
private readonly _dataTypes: DataTypeSchema[] = [];
|
|
22
|
+
private readonly _dimensions: DimensionSchema[] = [];
|
|
23
|
+
private readonly _transportations: TransportationSchema[] = [];
|
|
24
|
+
private _switches?: FomModel["switches"];
|
|
25
|
+
|
|
26
|
+
setModelIdentification(model: ModelIdentification): void {
|
|
27
|
+
this._modelIdentification = model;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setTime(time: TimeDefinition): void {
|
|
31
|
+
this._time = time;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
addObjectClass(schema: ObjectClassSchema): void {
|
|
35
|
+
validateName(schema.name, "object class");
|
|
36
|
+
this._objectClasses.push(schema);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
addInteractionClass(schema: InteractionClassSchema): void {
|
|
40
|
+
validateName(schema.name, "interaction class");
|
|
41
|
+
this._interactionClasses.push(schema);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
addDataType(schema: DataTypeSchema): void {
|
|
45
|
+
validateName(schema.name, "data type");
|
|
46
|
+
this._dataTypes.push(schema);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
addDimension(schema: DimensionSchema): void {
|
|
50
|
+
validateName(schema.name, "dimension");
|
|
51
|
+
this._dimensions.push(schema);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
addTransportation(schema: TransportationSchema): void {
|
|
55
|
+
validateName(schema.name, "transportation");
|
|
56
|
+
this._transportations.push(schema);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setSwitches(switches: FomModel["switches"]): void {
|
|
60
|
+
this._switches = switches ?? undefined;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
buildModel(): FomModel {
|
|
64
|
+
return {
|
|
65
|
+
modelIdentification: this._modelIdentification,
|
|
66
|
+
time: this._time,
|
|
67
|
+
objectClasses: [...this._objectClasses],
|
|
68
|
+
interactionClasses: [...this._interactionClasses],
|
|
69
|
+
dataTypes: [...this._dataTypes],
|
|
70
|
+
dimensions: [...this._dimensions],
|
|
71
|
+
transportations: [...this._transportations],
|
|
72
|
+
switches: this._switches,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
toXml(options: FomOutputOptions): string {
|
|
77
|
+
if (options.format === "omt") {
|
|
78
|
+
assertModelIdentification(this._modelIdentification);
|
|
79
|
+
}
|
|
80
|
+
return renderFomXml(this.buildModel(), options);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const defaultRegistry = new FomRegistry();
|
|
85
|
+
|
|
86
|
+
export function defineObjectClass<T extends new (...args: never[]) => unknown>(
|
|
87
|
+
ctor: T,
|
|
88
|
+
schema: ObjectClassSchema,
|
|
89
|
+
registry: FomRegistry = defaultRegistry
|
|
90
|
+
): T {
|
|
91
|
+
registry.addObjectClass(schema);
|
|
92
|
+
return ctor;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function defineInteractionClass<T extends new (...args: never[]) => unknown>(
|
|
96
|
+
ctor: T,
|
|
97
|
+
schema: InteractionClassSchema,
|
|
98
|
+
registry: FomRegistry = defaultRegistry
|
|
99
|
+
): T {
|
|
100
|
+
registry.addInteractionClass(schema);
|
|
101
|
+
return ctor;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function validateName(name: string, label: string): void {
|
|
105
|
+
if (!NCNAME_PATTERN.test(name)) {
|
|
106
|
+
throw new Error(`Invalid ${label} name "${name}". Expected XML NCName.`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function assertModelIdentification(model?: ModelIdentification): void {
|
|
111
|
+
if (!model) {
|
|
112
|
+
throw new Error("Model identification is required for OMT output.");
|
|
113
|
+
}
|
|
114
|
+
const required: Array<keyof ModelIdentification> = [
|
|
115
|
+
"name",
|
|
116
|
+
"type",
|
|
117
|
+
"version",
|
|
118
|
+
"modificationDate",
|
|
119
|
+
"securityClassification",
|
|
120
|
+
"description",
|
|
121
|
+
];
|
|
122
|
+
for (const key of required) {
|
|
123
|
+
if (!model[key]) {
|
|
124
|
+
throw new Error(`Model identification is missing required field: ${String(key)}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { FomModel } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
export type TsCodegenMode = "model" | "registry";
|
|
4
|
+
|
|
5
|
+
export interface TsCodegenOptions {
|
|
6
|
+
mode?: TsCodegenMode;
|
|
7
|
+
exportName?: string;
|
|
8
|
+
indent?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function generateFomTypescript(model: FomModel, options?: TsCodegenOptions): string {
|
|
12
|
+
const mode = options?.mode ?? "model";
|
|
13
|
+
const exportName = options?.exportName ?? (mode === "registry" ? "registry" : "fom");
|
|
14
|
+
const indent = options?.indent ?? 2;
|
|
15
|
+
const json = JSON.stringify(model, null, indent);
|
|
16
|
+
|
|
17
|
+
if (mode === "model") {
|
|
18
|
+
return [
|
|
19
|
+
'import type { FomModel } from "@hla4ts/fom-codegen";',
|
|
20
|
+
"",
|
|
21
|
+
`export const ${exportName}: FomModel = ${json};`,
|
|
22
|
+
"",
|
|
23
|
+
`export function buildFom(): FomModel {`,
|
|
24
|
+
` return ${exportName};`,
|
|
25
|
+
`}`,
|
|
26
|
+
"",
|
|
27
|
+
].join("\n");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return [
|
|
31
|
+
'import { FomRegistry } from "@hla4ts/fom-codegen";',
|
|
32
|
+
'import type { FomModel } from "@hla4ts/fom-codegen";',
|
|
33
|
+
"",
|
|
34
|
+
`const model: FomModel = ${json};`,
|
|
35
|
+
"",
|
|
36
|
+
`export const ${exportName} = new FomRegistry();`,
|
|
37
|
+
`if (model.modelIdentification) ${exportName}.setModelIdentification(model.modelIdentification);`,
|
|
38
|
+
`if (model.time) ${exportName}.setTime(model.time);`,
|
|
39
|
+
"for (const obj of model.objectClasses) {",
|
|
40
|
+
` ${exportName}.addObjectClass(obj);`,
|
|
41
|
+
"}",
|
|
42
|
+
"for (const interaction of model.interactionClasses) {",
|
|
43
|
+
` ${exportName}.addInteractionClass(interaction);`,
|
|
44
|
+
"}",
|
|
45
|
+
"for (const dataType of model.dataTypes) {",
|
|
46
|
+
` ${exportName}.addDataType(dataType);`,
|
|
47
|
+
"}",
|
|
48
|
+
"for (const dim of model.dimensions ?? []) {",
|
|
49
|
+
` ${exportName}.addDimension(dim);`,
|
|
50
|
+
"}",
|
|
51
|
+
"for (const transport of model.transportations ?? []) {",
|
|
52
|
+
` ${exportName}.addTransportation(transport);`,
|
|
53
|
+
"}",
|
|
54
|
+
"if (model.switches) {",
|
|
55
|
+
` ${exportName}.setSwitches(model.switches);`,
|
|
56
|
+
"}",
|
|
57
|
+
"",
|
|
58
|
+
].join("\n");
|
|
59
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FOM Codegen Types
|
|
3
|
+
*
|
|
4
|
+
* These types define a minimal, explicit schema for generating IEEE 1516-2025
|
|
5
|
+
* OMT/FDD XML from TypeScript registrations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export type SharingType = "Publish" | "Subscribe" | "PublishSubscribe" | "Neither";
|
|
9
|
+
export type OrderType = "Receive" | "TimeStamp";
|
|
10
|
+
export type UpdateType = "Static" | "Periodic" | "Conditional" | "NA";
|
|
11
|
+
export type OwnershipType = "Divest" | "Acquire" | "DivestAcquire" | "NoTransfer";
|
|
12
|
+
|
|
13
|
+
export interface ModelIdentification {
|
|
14
|
+
name: string;
|
|
15
|
+
type: "FOM" | "SOM";
|
|
16
|
+
version: string;
|
|
17
|
+
modificationDate: string; // YYYY-MM-DD
|
|
18
|
+
securityClassification: string;
|
|
19
|
+
description: string;
|
|
20
|
+
purpose?: string;
|
|
21
|
+
applicationDomain?: string;
|
|
22
|
+
useLimitation?: string;
|
|
23
|
+
keyword?: Array<{ taxonomy?: string; keywordValue: string }>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TimeDefinition {
|
|
27
|
+
timeStampType: string;
|
|
28
|
+
lookaheadType: string;
|
|
29
|
+
semantics?: {
|
|
30
|
+
timeStamp?: string;
|
|
31
|
+
lookahead?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface AttributeSchema {
|
|
36
|
+
name: string;
|
|
37
|
+
dataType: string;
|
|
38
|
+
updateType: UpdateType;
|
|
39
|
+
updateCondition: string;
|
|
40
|
+
ownership: OwnershipType;
|
|
41
|
+
sharing: SharingType;
|
|
42
|
+
transportation: string;
|
|
43
|
+
order: OrderType;
|
|
44
|
+
semantics?: string;
|
|
45
|
+
valueRequired?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface ObjectClassSchema {
|
|
49
|
+
name: string;
|
|
50
|
+
parent?: string;
|
|
51
|
+
sharing?: SharingType;
|
|
52
|
+
semantics?: string;
|
|
53
|
+
attributes?: AttributeSchema[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface ParameterSchema {
|
|
57
|
+
name: string;
|
|
58
|
+
dataType: string;
|
|
59
|
+
semantics?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface InteractionClassSchema {
|
|
63
|
+
name: string;
|
|
64
|
+
parent?: string;
|
|
65
|
+
sharing?: SharingType;
|
|
66
|
+
transportation?: string;
|
|
67
|
+
order?: OrderType;
|
|
68
|
+
semantics?: string;
|
|
69
|
+
parameters?: ParameterSchema[];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface DimensionSchema {
|
|
73
|
+
name: string;
|
|
74
|
+
dataType?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface TransportationSchema {
|
|
78
|
+
name: string;
|
|
79
|
+
reliable?: "Yes" | "No";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface SwitchesSchema {
|
|
83
|
+
autoProvide?: boolean;
|
|
84
|
+
conveyRegionDesignatorSets?: boolean;
|
|
85
|
+
conveyProducingFederate?: boolean;
|
|
86
|
+
attributeScopeAdvisory?: boolean;
|
|
87
|
+
attributeRelevanceAdvisory?: boolean;
|
|
88
|
+
objectClassRelevanceAdvisory?: boolean;
|
|
89
|
+
interactionRelevanceAdvisory?: boolean;
|
|
90
|
+
serviceReporting?: boolean;
|
|
91
|
+
exceptionReporting?: boolean;
|
|
92
|
+
delaySubscriptionEvaluation?: boolean;
|
|
93
|
+
automaticResignAction?: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface SimpleDataTypeSchema {
|
|
97
|
+
kind: "simple";
|
|
98
|
+
name: string;
|
|
99
|
+
representation: string;
|
|
100
|
+
units?: string;
|
|
101
|
+
resolution?: string;
|
|
102
|
+
accuracy?: string;
|
|
103
|
+
semantics?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface EnumeratedDataTypeSchema {
|
|
107
|
+
kind: "enumerated";
|
|
108
|
+
name: string;
|
|
109
|
+
representation: string;
|
|
110
|
+
semantics?: string;
|
|
111
|
+
enumerators: Array<{ name: string; value: string | string[] }>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface ArrayDataTypeSchema {
|
|
115
|
+
kind: "array";
|
|
116
|
+
name: string;
|
|
117
|
+
dataType: string;
|
|
118
|
+
cardinality: string;
|
|
119
|
+
encoding: string;
|
|
120
|
+
semantics?: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface FixedRecordDataTypeSchema {
|
|
124
|
+
kind: "fixedRecord";
|
|
125
|
+
name: string;
|
|
126
|
+
encoding: string;
|
|
127
|
+
semantics?: string;
|
|
128
|
+
fields: Array<{ name: string; dataType: string; semantics?: string }>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface VariantRecordDataTypeSchema {
|
|
132
|
+
kind: "variantRecord";
|
|
133
|
+
name: string;
|
|
134
|
+
discriminant: string;
|
|
135
|
+
dataType: string;
|
|
136
|
+
encoding: string;
|
|
137
|
+
semantics?: string;
|
|
138
|
+
alternatives: Array<{
|
|
139
|
+
enumerator: string;
|
|
140
|
+
name?: string;
|
|
141
|
+
dataType?: string;
|
|
142
|
+
semantics?: string;
|
|
143
|
+
}>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type DataTypeSchema =
|
|
147
|
+
| SimpleDataTypeSchema
|
|
148
|
+
| EnumeratedDataTypeSchema
|
|
149
|
+
| ArrayDataTypeSchema
|
|
150
|
+
| FixedRecordDataTypeSchema
|
|
151
|
+
| VariantRecordDataTypeSchema;
|
|
152
|
+
|
|
153
|
+
export interface FomModel {
|
|
154
|
+
modelIdentification?: ModelIdentification;
|
|
155
|
+
time?: TimeDefinition;
|
|
156
|
+
objectClasses: ObjectClassSchema[];
|
|
157
|
+
interactionClasses: InteractionClassSchema[];
|
|
158
|
+
dataTypes: DataTypeSchema[];
|
|
159
|
+
dimensions?: DimensionSchema[];
|
|
160
|
+
transportations?: TransportationSchema[];
|
|
161
|
+
switches?: SwitchesSchema;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export type FomOutputFormat = "omt" | "fdd";
|
|
165
|
+
|
|
166
|
+
export interface FomOutputOptions {
|
|
167
|
+
format: FomOutputFormat;
|
|
168
|
+
schemaLocation?: string;
|
|
169
|
+
includeModelIdentification?: boolean;
|
|
170
|
+
indent?: string;
|
|
171
|
+
inferParentStubs?: boolean;
|
|
172
|
+
}
|