@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.
Files changed (49) hide show
  1. package/INTEGRATION.md +354 -0
  2. package/LICENSE +373 -0
  3. package/README.md +101 -0
  4. package/dist/cli.d.ts +3 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +35 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/express-parser.d.ts +75 -0
  9. package/dist/express-parser.d.ts.map +1 -0
  10. package/dist/express-parser.js +318 -0
  11. package/dist/express-parser.js.map +1 -0
  12. package/dist/generator.d.ts +10 -0
  13. package/dist/generator.d.ts.map +1 -0
  14. package/dist/generator.js +64 -0
  15. package/dist/generator.js.map +1 -0
  16. package/dist/index.d.ts +9 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +12 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/typescript-generator.d.ts +28 -0
  21. package/dist/typescript-generator.d.ts.map +1 -0
  22. package/dist/typescript-generator.js +400 -0
  23. package/dist/typescript-generator.js.map +1 -0
  24. package/generated/ifc4/entities.ts +6978 -0
  25. package/generated/ifc4/enums.ts +2471 -0
  26. package/generated/ifc4/index.ts +15 -0
  27. package/generated/ifc4/schema-registry.ts +60726 -0
  28. package/generated/ifc4/selects.ts +191 -0
  29. package/generated/ifc4/test-compile.ts +37 -0
  30. package/generated/ifc4/types.ts +3104 -0
  31. package/generated/ifc4x3/entities.ts +7836 -0
  32. package/generated/ifc4x3/enums.ts +3100 -0
  33. package/generated/ifc4x3/index.ts +15 -0
  34. package/generated/ifc4x3/schema-registry.ts +71023 -0
  35. package/generated/ifc4x3/selects.ts +194 -0
  36. package/generated/ifc4x3/types.ts +3707 -0
  37. package/package.json +32 -0
  38. package/schemas/IFC4X3.exp +13984 -0
  39. package/schemas/IFC4_ADD2_TC1.exp +12399 -0
  40. package/src/cli.ts +41 -0
  41. package/src/express-parser.ts +441 -0
  42. package/src/generator.ts +81 -0
  43. package/src/index.ts +31 -0
  44. package/src/typescript-generator.ts +496 -0
  45. package/test/express-parser.test.ts +363 -0
  46. package/test/integration.test.ts +246 -0
  47. package/test/typescript-generator.test.ts +348 -0
  48. package/tsconfig.json +20 -0
  49. 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
+ }
@@ -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
+ });