@ifc-lite/codegen 1.0.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/INTEGRATION.md +354 -0
- package/LICENSE +373 -0
- package/README.md +101 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -0
- package/dist/express-parser.d.ts +75 -0
- package/dist/express-parser.d.ts.map +1 -0
- package/dist/express-parser.js +318 -0
- package/dist/express-parser.js.map +1 -0
- package/dist/generator.d.ts +10 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +64 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/typescript-generator.d.ts +28 -0
- package/dist/typescript-generator.d.ts.map +1 -0
- package/dist/typescript-generator.js +400 -0
- package/dist/typescript-generator.js.map +1 -0
- package/generated/ifc4/entities.ts +6978 -0
- package/generated/ifc4/enums.ts +2471 -0
- package/generated/ifc4/index.ts +15 -0
- package/generated/ifc4/schema-registry.ts +60726 -0
- package/generated/ifc4/selects.ts +191 -0
- package/generated/ifc4/test-compile.ts +37 -0
- package/generated/ifc4/types.ts +3104 -0
- package/generated/ifc4x3/entities.ts +7836 -0
- package/generated/ifc4x3/enums.ts +3100 -0
- package/generated/ifc4x3/index.ts +15 -0
- package/generated/ifc4x3/schema-registry.ts +71023 -0
- package/generated/ifc4x3/selects.ts +194 -0
- package/generated/ifc4x3/types.ts +3707 -0
- package/package.json +32 -0
- package/schemas/IFC4X3.exp +13984 -0
- package/schemas/IFC4_ADD2_TC1.exp +12399 -0
- package/src/cli.ts +41 -0
- package/src/express-parser.ts +441 -0
- package/src/generator.ts +81 -0
- package/src/index.ts +31 -0
- package/src/typescript-generator.ts +496 -0
- package/test/express-parser.test.ts +363 -0
- package/test/integration.test.ts +246 -0
- package/test/typescript-generator.test.ts +348 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +18 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Tests for TypeScript generator
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect } from 'vitest';
|
|
10
|
+
import { parseExpressSchema } from '../src/express-parser.js';
|
|
11
|
+
import { generateTypeScript } from '../src/typescript-generator.js';
|
|
12
|
+
|
|
13
|
+
describe('TypeScript Generator', () => {
|
|
14
|
+
describe('Entity interface generation', () => {
|
|
15
|
+
it('should generate simple interface', () => {
|
|
16
|
+
const schema = parseExpressSchema(`
|
|
17
|
+
SCHEMA TEST;
|
|
18
|
+
|
|
19
|
+
ENTITY IfcRoot;
|
|
20
|
+
GlobalId : IfcGloballyUniqueId;
|
|
21
|
+
Name : OPTIONAL IfcLabel;
|
|
22
|
+
END_ENTITY;
|
|
23
|
+
|
|
24
|
+
END_SCHEMA;
|
|
25
|
+
`);
|
|
26
|
+
|
|
27
|
+
const code = generateTypeScript(schema);
|
|
28
|
+
|
|
29
|
+
expect(code.entities).toContain('export interface IfcRoot');
|
|
30
|
+
expect(code.entities).toContain('GlobalId: IfcGloballyUniqueId;');
|
|
31
|
+
expect(code.entities).toContain('Name?: IfcLabel;');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should generate interface with inheritance', () => {
|
|
35
|
+
const schema = parseExpressSchema(`
|
|
36
|
+
SCHEMA TEST;
|
|
37
|
+
|
|
38
|
+
ENTITY IfcRoot;
|
|
39
|
+
GlobalId : IfcGloballyUniqueId;
|
|
40
|
+
END_ENTITY;
|
|
41
|
+
|
|
42
|
+
ENTITY IfcObject
|
|
43
|
+
SUBTYPE OF (IfcRoot);
|
|
44
|
+
ObjectType : OPTIONAL IfcLabel;
|
|
45
|
+
END_ENTITY;
|
|
46
|
+
|
|
47
|
+
END_SCHEMA;
|
|
48
|
+
`);
|
|
49
|
+
|
|
50
|
+
const code = generateTypeScript(schema);
|
|
51
|
+
|
|
52
|
+
expect(code.entities).toContain('export interface IfcObject extends IfcRoot');
|
|
53
|
+
expect(code.entities).toContain('ObjectType?: IfcLabel;');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should generate JSDoc comments', () => {
|
|
57
|
+
const schema = parseExpressSchema(`
|
|
58
|
+
SCHEMA TEST;
|
|
59
|
+
|
|
60
|
+
ENTITY IfcRoot
|
|
61
|
+
ABSTRACT;
|
|
62
|
+
GlobalId : IfcGloballyUniqueId;
|
|
63
|
+
END_ENTITY;
|
|
64
|
+
|
|
65
|
+
END_SCHEMA;
|
|
66
|
+
`);
|
|
67
|
+
|
|
68
|
+
const code = generateTypeScript(schema);
|
|
69
|
+
|
|
70
|
+
expect(code.entities).toContain('/**');
|
|
71
|
+
expect(code.entities).toContain('* IfcRoot');
|
|
72
|
+
expect(code.entities).toContain('* @abstract');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should handle array attributes', () => {
|
|
76
|
+
const schema = parseExpressSchema(`
|
|
77
|
+
SCHEMA TEST;
|
|
78
|
+
|
|
79
|
+
ENTITY IfcTest;
|
|
80
|
+
Items : LIST [1:?] OF IfcCartesianPoint;
|
|
81
|
+
Coords : ARRAY [1:3] OF REAL;
|
|
82
|
+
Tags : SET [0:?] OF IfcLabel;
|
|
83
|
+
END_ENTITY;
|
|
84
|
+
|
|
85
|
+
END_SCHEMA;
|
|
86
|
+
`);
|
|
87
|
+
|
|
88
|
+
const code = generateTypeScript(schema);
|
|
89
|
+
|
|
90
|
+
expect(code.entities).toContain('Items: IfcCartesianPoint[];');
|
|
91
|
+
expect(code.entities).toContain('Coords: number[];');
|
|
92
|
+
expect(code.entities).toContain('Tags: IfcLabel[];');
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should map EXPRESS types to TypeScript types', () => {
|
|
96
|
+
const schema = parseExpressSchema(`
|
|
97
|
+
SCHEMA TEST;
|
|
98
|
+
|
|
99
|
+
ENTITY IfcTest;
|
|
100
|
+
RealValue : REAL;
|
|
101
|
+
IntValue : INTEGER;
|
|
102
|
+
BoolValue : BOOLEAN;
|
|
103
|
+
StrValue : STRING;
|
|
104
|
+
END_ENTITY;
|
|
105
|
+
|
|
106
|
+
END_SCHEMA;
|
|
107
|
+
`);
|
|
108
|
+
|
|
109
|
+
const code = generateTypeScript(schema);
|
|
110
|
+
|
|
111
|
+
expect(code.entities).toContain('RealValue: number;');
|
|
112
|
+
expect(code.entities).toContain('IntValue: number;');
|
|
113
|
+
expect(code.entities).toContain('BoolValue: boolean;');
|
|
114
|
+
expect(code.entities).toContain('StrValue: string;');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('Type alias generation', () => {
|
|
119
|
+
it('should generate type aliases', () => {
|
|
120
|
+
const schema = parseExpressSchema(`
|
|
121
|
+
SCHEMA TEST;
|
|
122
|
+
|
|
123
|
+
TYPE IfcLabel = STRING;
|
|
124
|
+
END_TYPE;
|
|
125
|
+
|
|
126
|
+
TYPE IfcLengthMeasure = REAL;
|
|
127
|
+
END_TYPE;
|
|
128
|
+
|
|
129
|
+
END_SCHEMA;
|
|
130
|
+
`);
|
|
131
|
+
|
|
132
|
+
const code = generateTypeScript(schema);
|
|
133
|
+
|
|
134
|
+
expect(code.types).toContain('export type IfcLabel = string;');
|
|
135
|
+
expect(code.types).toContain('export type IfcLengthMeasure = number;');
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe('Enum generation', () => {
|
|
140
|
+
it('should generate enums', () => {
|
|
141
|
+
const schema = parseExpressSchema(`
|
|
142
|
+
SCHEMA TEST;
|
|
143
|
+
|
|
144
|
+
TYPE IfcWallTypeEnum = ENUMERATION OF
|
|
145
|
+
(MOVABLE
|
|
146
|
+
,PARAPET
|
|
147
|
+
,SOLIDWALL);
|
|
148
|
+
END_TYPE;
|
|
149
|
+
|
|
150
|
+
END_SCHEMA;
|
|
151
|
+
`);
|
|
152
|
+
|
|
153
|
+
const code = generateTypeScript(schema);
|
|
154
|
+
|
|
155
|
+
expect(code.enums).toContain('export enum IfcWallTypeEnum');
|
|
156
|
+
expect(code.enums).toContain("MOVABLE = 'MOVABLE'");
|
|
157
|
+
expect(code.enums).toContain("PARAPET = 'PARAPET'");
|
|
158
|
+
expect(code.enums).toContain("SOLIDWALL = 'SOLIDWALL'");
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('Select type generation', () => {
|
|
163
|
+
it('should generate union types', () => {
|
|
164
|
+
const schema = parseExpressSchema(`
|
|
165
|
+
SCHEMA TEST;
|
|
166
|
+
|
|
167
|
+
TYPE IfcValue = SELECT
|
|
168
|
+
(IfcLabel
|
|
169
|
+
,IfcInteger
|
|
170
|
+
,IfcReal);
|
|
171
|
+
END_TYPE;
|
|
172
|
+
|
|
173
|
+
END_SCHEMA;
|
|
174
|
+
`);
|
|
175
|
+
|
|
176
|
+
const code = generateTypeScript(schema);
|
|
177
|
+
|
|
178
|
+
expect(code.selects).toContain('export type IfcValue =');
|
|
179
|
+
expect(code.selects).toContain('IfcLabel | IfcInteger | IfcReal');
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('Schema registry generation', () => {
|
|
184
|
+
it('should generate schema registry', () => {
|
|
185
|
+
const schema = parseExpressSchema(`
|
|
186
|
+
SCHEMA TEST;
|
|
187
|
+
|
|
188
|
+
ENTITY IfcRoot;
|
|
189
|
+
GlobalId : IfcGloballyUniqueId;
|
|
190
|
+
Name : OPTIONAL IfcLabel;
|
|
191
|
+
END_ENTITY;
|
|
192
|
+
|
|
193
|
+
END_SCHEMA;
|
|
194
|
+
`);
|
|
195
|
+
|
|
196
|
+
const code = generateTypeScript(schema);
|
|
197
|
+
|
|
198
|
+
expect(code.schemaRegistry).toContain('export const SCHEMA_REGISTRY');
|
|
199
|
+
expect(code.schemaRegistry).toContain("name: 'TEST'");
|
|
200
|
+
expect(code.schemaRegistry).toContain('IfcRoot: {');
|
|
201
|
+
expect(code.schemaRegistry).toContain("name: 'IfcRoot'");
|
|
202
|
+
expect(code.schemaRegistry).toContain("name: 'GlobalId'");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should include inheritance chain in registry', () => {
|
|
206
|
+
const schema = parseExpressSchema(`
|
|
207
|
+
SCHEMA TEST;
|
|
208
|
+
|
|
209
|
+
ENTITY IfcRoot;
|
|
210
|
+
GlobalId : IfcGloballyUniqueId;
|
|
211
|
+
END_ENTITY;
|
|
212
|
+
|
|
213
|
+
ENTITY IfcObject
|
|
214
|
+
SUBTYPE OF (IfcRoot);
|
|
215
|
+
ObjectType : OPTIONAL IfcLabel;
|
|
216
|
+
END_ENTITY;
|
|
217
|
+
|
|
218
|
+
END_SCHEMA;
|
|
219
|
+
`);
|
|
220
|
+
|
|
221
|
+
const code = generateTypeScript(schema);
|
|
222
|
+
|
|
223
|
+
expect(code.schemaRegistry).toContain("inheritanceChain: ['IfcRoot', 'IfcObject']");
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should include allAttributes in registry', () => {
|
|
227
|
+
const schema = parseExpressSchema(`
|
|
228
|
+
SCHEMA TEST;
|
|
229
|
+
|
|
230
|
+
ENTITY IfcRoot;
|
|
231
|
+
GlobalId : IfcGloballyUniqueId;
|
|
232
|
+
END_ENTITY;
|
|
233
|
+
|
|
234
|
+
ENTITY IfcObject
|
|
235
|
+
SUBTYPE OF (IfcRoot);
|
|
236
|
+
ObjectType : OPTIONAL IfcLabel;
|
|
237
|
+
END_ENTITY;
|
|
238
|
+
|
|
239
|
+
END_SCHEMA;
|
|
240
|
+
`);
|
|
241
|
+
|
|
242
|
+
const code = generateTypeScript(schema);
|
|
243
|
+
|
|
244
|
+
// IfcObject should have allAttributes including GlobalId from parent
|
|
245
|
+
expect(code.schemaRegistry).toContain('allAttributes: [');
|
|
246
|
+
expect(code.schemaRegistry).toMatch(/IfcObject[\s\S]*allAttributes:[\s\S]*GlobalId/);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('should generate helper functions', () => {
|
|
250
|
+
const schema = parseExpressSchema(`
|
|
251
|
+
SCHEMA TEST;
|
|
252
|
+
ENTITY IfcRoot;
|
|
253
|
+
GlobalId : IfcGloballyUniqueId;
|
|
254
|
+
END_ENTITY;
|
|
255
|
+
END_SCHEMA;
|
|
256
|
+
`);
|
|
257
|
+
|
|
258
|
+
const code = generateTypeScript(schema);
|
|
259
|
+
|
|
260
|
+
expect(code.schemaRegistry).toContain('export function getEntityMetadata');
|
|
261
|
+
expect(code.schemaRegistry).toContain('export function getAllAttributesForEntity');
|
|
262
|
+
expect(code.schemaRegistry).toContain('export function getInheritanceChainForEntity');
|
|
263
|
+
expect(code.schemaRegistry).toContain('export function isKnownEntity');
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe('Full generation', () => {
|
|
268
|
+
it('should generate all code sections', () => {
|
|
269
|
+
const schema = parseExpressSchema(`
|
|
270
|
+
SCHEMA TEST;
|
|
271
|
+
|
|
272
|
+
TYPE IfcLabel = STRING;
|
|
273
|
+
END_TYPE;
|
|
274
|
+
|
|
275
|
+
TYPE IfcWallTypeEnum = ENUMERATION OF
|
|
276
|
+
(MOVABLE
|
|
277
|
+
,SOLIDWALL);
|
|
278
|
+
END_TYPE;
|
|
279
|
+
|
|
280
|
+
TYPE IfcValue = SELECT
|
|
281
|
+
(IfcLabel
|
|
282
|
+
,IfcInteger);
|
|
283
|
+
END_TYPE;
|
|
284
|
+
|
|
285
|
+
ENTITY IfcRoot;
|
|
286
|
+
GlobalId : IfcGloballyUniqueId;
|
|
287
|
+
Name : OPTIONAL IfcLabel;
|
|
288
|
+
END_ENTITY;
|
|
289
|
+
|
|
290
|
+
ENTITY IfcWall
|
|
291
|
+
SUBTYPE OF (IfcRoot);
|
|
292
|
+
PredefinedType : OPTIONAL IfcWallTypeEnum;
|
|
293
|
+
END_ENTITY;
|
|
294
|
+
|
|
295
|
+
END_SCHEMA;
|
|
296
|
+
`);
|
|
297
|
+
|
|
298
|
+
const code = generateTypeScript(schema);
|
|
299
|
+
|
|
300
|
+
// Check all sections are generated
|
|
301
|
+
expect(code.entities).toBeTruthy();
|
|
302
|
+
expect(code.types).toBeTruthy();
|
|
303
|
+
expect(code.enums).toBeTruthy();
|
|
304
|
+
expect(code.selects).toBeTruthy();
|
|
305
|
+
expect(code.schemaRegistry).toBeTruthy();
|
|
306
|
+
|
|
307
|
+
// Check content
|
|
308
|
+
expect(code.entities).toContain('export interface IfcRoot');
|
|
309
|
+
expect(code.entities).toContain('export interface IfcWall extends IfcRoot');
|
|
310
|
+
expect(code.types).toContain('export type IfcLabel = string');
|
|
311
|
+
expect(code.enums).toContain('export enum IfcWallTypeEnum');
|
|
312
|
+
expect(code.selects).toContain('export type IfcValue');
|
|
313
|
+
expect(code.schemaRegistry).toContain('SCHEMA_REGISTRY');
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe('Edge cases', () => {
|
|
318
|
+
it('should handle entities with no attributes', () => {
|
|
319
|
+
const schema = parseExpressSchema(`
|
|
320
|
+
SCHEMA TEST;
|
|
321
|
+
|
|
322
|
+
ENTITY IfcEmpty;
|
|
323
|
+
END_ENTITY;
|
|
324
|
+
|
|
325
|
+
END_SCHEMA;
|
|
326
|
+
`);
|
|
327
|
+
|
|
328
|
+
const code = generateTypeScript(schema);
|
|
329
|
+
|
|
330
|
+
expect(code.entities).toContain('export interface IfcEmpty');
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('should handle empty schema', () => {
|
|
334
|
+
const schema = parseExpressSchema(`
|
|
335
|
+
SCHEMA TEST;
|
|
336
|
+
END_SCHEMA;
|
|
337
|
+
`);
|
|
338
|
+
|
|
339
|
+
const code = generateTypeScript(schema);
|
|
340
|
+
|
|
341
|
+
expect(code.entities).toBeTruthy();
|
|
342
|
+
expect(code.types).toBeTruthy();
|
|
343
|
+
expect(code.enums).toBeTruthy();
|
|
344
|
+
expect(code.selects).toBeTruthy();
|
|
345
|
+
expect(code.schemaRegistry).toBeTruthy();
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"resolveJsonModule": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "test"]
|
|
20
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
import { defineConfig } from 'vitest/config';
|
|
6
|
+
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
test: {
|
|
9
|
+
globals: true,
|
|
10
|
+
environment: 'node',
|
|
11
|
+
include: ['test/**/*.test.ts'],
|
|
12
|
+
coverage: {
|
|
13
|
+
provider: 'v8',
|
|
14
|
+
reporter: ['text', 'html'],
|
|
15
|
+
exclude: ['dist/**', 'generated/**', 'test/**'],
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|