@ifc-lite/codegen 1.15.4 → 1.15.6

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 (38) hide show
  1. package/README.md +18 -15
  2. package/package.json +16 -6
  3. package/.turbo/turbo-build.log +0 -4
  4. package/CHANGELOG.md +0 -165
  5. package/INTEGRATION.md +0 -360
  6. package/generated/ifc4/entities.ts +0 -7400
  7. package/generated/ifc4/enums.ts +0 -2467
  8. package/generated/ifc4/index.ts +0 -17
  9. package/generated/ifc4/schema-registry.ts +0 -63186
  10. package/generated/ifc4/selects.ts +0 -315
  11. package/generated/ifc4/serializers.ts +0 -51
  12. package/generated/ifc4/test-compile.ts +0 -49
  13. package/generated/ifc4/type-ids.ts +0 -1682
  14. package/generated/ifc4/types.ts +0 -401
  15. package/generated/ifc4x3/entities.ts +0 -8300
  16. package/generated/ifc4x3/enums.ts +0 -3096
  17. package/generated/ifc4x3/index.ts +0 -17
  18. package/generated/ifc4x3/schema-registry.ts +0 -71489
  19. package/generated/ifc4x3/selects.ts +0 -312
  20. package/generated/ifc4x3/serializers.ts +0 -51
  21. package/generated/ifc4x3/test-compile.ts +0 -49
  22. package/generated/ifc4x3/type-ids.ts +0 -1882
  23. package/generated/ifc4x3/types.ts +0 -407
  24. package/src/cli.ts +0 -72
  25. package/src/crc32.ts +0 -77
  26. package/src/express-parser.ts +0 -457
  27. package/src/generator.ts +0 -268
  28. package/src/index.ts +0 -57
  29. package/src/rust-generator.ts +0 -714
  30. package/src/serialization-generator.ts +0 -74
  31. package/src/type-ids-generator.ts +0 -166
  32. package/src/typescript-generator.ts +0 -631
  33. package/test/express-parser.test.ts +0 -363
  34. package/test/integration.test.ts +0 -246
  35. package/test/serialization-generator.test.ts +0 -65
  36. package/test/typescript-generator.test.ts +0 -348
  37. package/tsconfig.json +0 -21
  38. package/vitest.config.ts +0 -18
@@ -1,714 +0,0 @@
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
- * Rust Code Generator
7
- *
8
- * Generates Rust types from EXPRESS schema for:
9
- * - Type IDs (CRC32 constants)
10
- * - IfcType enum with all variants
11
- * - Geometry category classification
12
- * - Type conversion functions
13
- */
14
-
15
- import type { ExpressSchema, EntityDefinition } from './express-parser.js';
16
- import { crc32 } from './crc32.js';
17
- import { getInheritanceChain } from './express-parser.js';
18
-
19
- export interface RustGeneratedCode {
20
- typeIds: string;
21
- schema: string;
22
- }
23
-
24
- /**
25
- * Generate all Rust code from EXPRESS schema
26
- */
27
- export function generateRust(schema: ExpressSchema): RustGeneratedCode {
28
- return {
29
- typeIds: generateTypeIdConstants(schema),
30
- schema: generateIfcTypeEnum(schema),
31
- };
32
- }
33
-
34
- /**
35
- * Generate CRC32 type ID constants
36
- */
37
- function generateTypeIdConstants(schema: ExpressSchema): string {
38
- let code = `// This Source Code Form is subject to the terms of the Mozilla Public
39
- // License, v. 2.0. If a copy of the MPL was not distributed with this
40
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
41
-
42
- //! Auto-generated IFC Type ID Constants
43
- //!
44
- //! CRC32 hashes for fast type identification.
45
- //! Generated from EXPRESS schema: ${schema.name}
46
- //!
47
- //! DO NOT EDIT - This file is auto-generated by @ifc-lite/codegen
48
-
49
- #![allow(dead_code)]
50
-
51
- `;
52
-
53
- // Group by category for readability
54
- const categories = categorizeEntities(schema);
55
-
56
- for (const [category, entities] of Object.entries(categories)) {
57
- code += `// ${category}\n`;
58
- for (const entity of entities) {
59
- const id = crc32(entity.name);
60
- code += `pub const ${entity.name.toUpperCase()}: u32 = ${id};\n`;
61
- }
62
- code += '\n';
63
- }
64
-
65
- return code;
66
- }
67
-
68
- /**
69
- * Generate the main IfcType enum
70
- */
71
- function generateIfcTypeEnum(schema: ExpressSchema): string {
72
- let code = `// This Source Code Form is subject to the terms of the Mozilla Public
73
- // License, v. 2.0. If a copy of the MPL was not distributed with this
74
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
75
-
76
- //! Auto-generated IFC Type Enum
77
- //!
78
- //! Generated from EXPRESS schema: ${schema.name}
79
- //!
80
- //! DO NOT EDIT - This file is auto-generated by @ifc-lite/codegen
81
-
82
- use std::fmt;
83
-
84
- /// IFC Entity Types
85
- ///
86
- /// All ${schema.entities.length} entity types from the ${schema.name} schema.
87
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
88
- pub enum IfcType {
89
- `;
90
-
91
- // Group entities by category
92
- const categories = categorizeEntities(schema);
93
-
94
- for (const [category, entities] of Object.entries(categories)) {
95
- code += ` // ${category}\n`;
96
- for (const entity of entities) {
97
- if (entity.isAbstract) {
98
- code += ` /// Abstract entity\n`;
99
- }
100
- code += ` ${entity.name},\n`;
101
- }
102
- code += '\n';
103
- }
104
-
105
- // Add Unknown variant for unrecognized types
106
- code += ` /// Unknown/unrecognized IFC type (stores CRC32 hash)
107
- Unknown(u32),
108
- }
109
-
110
- impl IfcType {
111
- /// Parse IFC type from string (case-insensitive)
112
- pub fn from_str(s: &str) -> Self {
113
- let upper = s.to_uppercase();
114
- match upper.as_str() {
115
- `;
116
-
117
- // Generate match arms for all entities
118
- for (const entity of schema.entities) {
119
- code += ` "${entity.name.toUpperCase()}" => Self::${entity.name},\n`;
120
- }
121
-
122
- code += ` _ => Self::Unknown(crc32_hash(&upper)),
123
- }
124
- }
125
-
126
- /// Parse from CRC32 type ID
127
- pub fn from_id(id: u32) -> Self {
128
- match id {
129
- `;
130
-
131
- // Generate match arms for CRC32 IDs
132
- for (const entity of schema.entities) {
133
- const id = crc32(entity.name);
134
- code += ` ${id} => Self::${entity.name},\n`;
135
- }
136
-
137
- code += ` _ => Self::Unknown(id),
138
- }
139
- }
140
-
141
- /// Get CRC32 type ID
142
- pub fn id(&self) -> u32 {
143
- match self {
144
- `;
145
-
146
- for (const entity of schema.entities) {
147
- const id = crc32(entity.name);
148
- code += ` Self::${entity.name} => ${id},\n`;
149
- }
150
-
151
- code += ` Self::Unknown(id) => *id,
152
- }
153
- }
154
-
155
- /// Get string representation (uppercase)
156
- pub fn as_str(&self) -> &'static str {
157
- match self {
158
- `;
159
-
160
- for (const entity of schema.entities) {
161
- code += ` Self::${entity.name} => "${entity.name.toUpperCase()}",\n`;
162
- }
163
-
164
- code += ` Self::Unknown(_) => "UNKNOWN",
165
- }
166
- }
167
-
168
- /// Get display name (PascalCase)
169
- pub fn name(&self) -> &'static str {
170
- match self {
171
- `;
172
-
173
- for (const entity of schema.entities) {
174
- code += ` Self::${entity.name} => "${entity.name}",\n`;
175
- }
176
-
177
- code += ` Self::Unknown(_) => "Unknown",
178
- }
179
- }
180
-
181
- /// Get parent type (if any)
182
- pub fn parent(&self) -> Option<Self> {
183
- match self {
184
- `;
185
-
186
- for (const entity of schema.entities) {
187
- if (entity.supertype) {
188
- code += ` Self::${entity.name} => Some(Self::${entity.supertype}),\n`;
189
- }
190
- }
191
-
192
- code += ` _ => None,
193
- }
194
- }
195
-
196
- /// Check if this type is a subtype of another
197
- pub fn is_subtype_of(&self, parent: Self) -> bool {
198
- let mut current = Some(*self);
199
- while let Some(t) = current {
200
- if t == parent {
201
- return true;
202
- }
203
- current = t.parent();
204
- }
205
- false
206
- }
207
-
208
- /// Check if this is an abstract type
209
- pub fn is_abstract(&self) -> bool {
210
- match self {
211
- `;
212
-
213
- const abstractTypes = schema.entities.filter((e) => e.isAbstract);
214
- for (const entity of abstractTypes) {
215
- code += ` Self::${entity.name} => true,\n`;
216
- }
217
-
218
- code += ` _ => false,
219
- }
220
- }
221
- }
222
-
223
- impl fmt::Display for IfcType {
224
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225
- write!(f, "{}", self.name())
226
- }
227
- }
228
-
229
- /// CRC32 hash function for unknown types
230
- fn crc32_hash(s: &str) -> u32 {
231
- const TABLE: [u32; 256] = [
232
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
233
- 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
234
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
235
- 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
236
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
237
- 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
238
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
239
- 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
240
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
241
- 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
242
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
243
- 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
244
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
245
- 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
246
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
247
- 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
248
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
249
- 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
250
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cd9, 0x5005713c, 0x270241aa,
251
- 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
252
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
253
- 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
254
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
255
- 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
256
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
257
- 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
258
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
259
- 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
260
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
261
- 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
262
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
263
- 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
264
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
265
- 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
266
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
267
- 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
268
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
269
- 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
270
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
271
- 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
272
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd706b3,
273
- 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
274
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
275
- ];
276
-
277
- let mut crc = 0xffffffffu32;
278
- for byte in s.bytes() {
279
- crc = TABLE[((crc ^ byte as u32) & 0xff) as usize] ^ (crc >> 8);
280
- }
281
- crc ^ 0xffffffff
282
- }
283
- `;
284
-
285
- return code;
286
- }
287
-
288
- /**
289
- * Generate geometry category classification
290
- * REMOVED: No longer generating geometry categories (unused code)
291
- */
292
- function _generateGeometryCategories_removed(schema: ExpressSchema): string {
293
- let code = `// This Source Code Form is subject to the terms of the Mozilla Public
294
- // License, v. 2.0. If a copy of the MPL was not distributed with this
295
- // file, You can obtain one at https://mozilla.org/MPL/2.0/.
296
-
297
- //! Auto-generated Geometry Category Classification
298
- //!
299
- //! Generated from EXPRESS schema: ${schema.name}
300
- //!
301
- //! DO NOT EDIT - This file is auto-generated by @ifc-lite/codegen
302
-
303
- use super::IfcType;
304
-
305
- /// Geometry representation categories
306
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
307
- pub enum GeometryCategory {
308
- /// Swept solids (extrusions, revolutions)
309
- SweptSolid,
310
- /// Boolean/CSG operations
311
- Boolean,
312
- /// Explicit mesh representations
313
- ExplicitMesh,
314
- /// Mapped/instanced geometry
315
- MappedItem,
316
- /// Surface models
317
- Surface,
318
- /// Curve geometry
319
- Curve,
320
- /// Other geometry types
321
- Other,
322
- }
323
-
324
- /// Profile definition categories
325
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
326
- pub enum ProfileCategory {
327
- /// Parametric profiles (rectangle, circle, I-shape, etc.)
328
- Parametric,
329
- /// Arbitrary closed profiles
330
- Arbitrary,
331
- /// Composite profiles
332
- Composite,
333
- }
334
-
335
- impl IfcType {
336
- /// Get geometry category for this type
337
- pub fn geometry_category(&self) -> Option<GeometryCategory> {
338
- match self {
339
- // Swept solids
340
- `;
341
-
342
- // Swept solids
343
- const sweptSolids = [
344
- 'IfcExtrudedAreaSolid',
345
- 'IfcExtrudedAreaSolidTapered',
346
- 'IfcRevolvedAreaSolid',
347
- 'IfcRevolvedAreaSolidTapered',
348
- 'IfcSurfaceCurveSweptAreaSolid',
349
- 'IfcFixedReferenceSweptAreaSolid',
350
- 'IfcSweptDiskSolid',
351
- 'IfcSweptDiskSolidPolygonal',
352
- ];
353
- for (const name of sweptSolids) {
354
- if (schema.entities.find((e) => e.name === name)) {
355
- code += ` Self::${name} => Some(GeometryCategory::SweptSolid),\n`;
356
- }
357
- }
358
-
359
- code += `
360
- // Boolean/CSG
361
- `;
362
-
363
- // Boolean types
364
- const booleanTypes = [
365
- 'IfcBooleanResult',
366
- 'IfcBooleanClippingResult',
367
- 'IfcCsgSolid',
368
- 'IfcCsgPrimitive3D',
369
- 'IfcBlock',
370
- 'IfcSphere',
371
- 'IfcRightCircularCone',
372
- 'IfcRightCircularCylinder',
373
- 'IfcRectangularPyramid',
374
- ];
375
- for (const name of booleanTypes) {
376
- if (schema.entities.find((e) => e.name === name)) {
377
- code += ` Self::${name} => Some(GeometryCategory::Boolean),\n`;
378
- }
379
- }
380
-
381
- code += `
382
- // Explicit mesh
383
- `;
384
-
385
- // Explicit mesh types
386
- const meshTypes = [
387
- 'IfcFacetedBrep',
388
- 'IfcFacetedBrepWithVoids',
389
- 'IfcAdvancedBrep',
390
- 'IfcAdvancedBrepWithVoids',
391
- 'IfcManifoldSolidBrep',
392
- 'IfcTriangulatedFaceSet',
393
- 'IfcPolygonalFaceSet',
394
- 'IfcTriangulatedIrregularNetwork',
395
- 'IfcTessellatedFaceSet',
396
- 'IfcIndexedPolygonalFace',
397
- 'IfcShellBasedSurfaceModel',
398
- 'IfcFaceBasedSurfaceModel',
399
- ];
400
- for (const name of meshTypes) {
401
- if (schema.entities.find((e) => e.name === name)) {
402
- code += ` Self::${name} => Some(GeometryCategory::ExplicitMesh),\n`;
403
- }
404
- }
405
-
406
- code += `
407
- // Mapped items
408
- `;
409
-
410
- if (schema.entities.find((e) => e.name === 'IfcMappedItem')) {
411
- code += ` Self::IfcMappedItem => Some(GeometryCategory::MappedItem),\n`;
412
- }
413
-
414
- code += `
415
- // Surfaces
416
- `;
417
-
418
- const surfaceTypes = [
419
- 'IfcBSplineSurface',
420
- 'IfcBSplineSurfaceWithKnots',
421
- 'IfcRationalBSplineSurfaceWithKnots',
422
- 'IfcCylindricalSurface',
423
- 'IfcSphericalSurface',
424
- 'IfcToroidalSurface',
425
- 'IfcPlane',
426
- 'IfcCurveBoundedPlane',
427
- 'IfcCurveBoundedSurface',
428
- 'IfcRectangularTrimmedSurface',
429
- 'IfcSurfaceOfLinearExtrusion',
430
- 'IfcSurfaceOfRevolution',
431
- ];
432
- for (const name of surfaceTypes) {
433
- if (schema.entities.find((e) => e.name === name)) {
434
- code += ` Self::${name} => Some(GeometryCategory::Surface),\n`;
435
- }
436
- }
437
-
438
- code += `
439
- // Curves
440
- `;
441
-
442
- const curveTypes = [
443
- 'IfcBSplineCurve',
444
- 'IfcBSplineCurveWithKnots',
445
- 'IfcRationalBSplineCurveWithKnots',
446
- 'IfcCompositeCurve',
447
- 'IfcPolyline',
448
- 'IfcTrimmedCurve',
449
- 'IfcCircle',
450
- 'IfcEllipse',
451
- 'IfcLine',
452
- 'IfcIndexedPolyCurve',
453
- ];
454
- for (const name of curveTypes) {
455
- if (schema.entities.find((e) => e.name === name)) {
456
- code += ` Self::${name} => Some(GeometryCategory::Curve),\n`;
457
- }
458
- }
459
-
460
- code += `
461
- _ => None,
462
- }
463
- }
464
-
465
- /// Get profile category for this type
466
- pub fn profile_category(&self) -> Option<ProfileCategory> {
467
- match self {
468
- // Parametric profiles
469
- `;
470
-
471
- const parametricProfiles = [
472
- 'IfcRectangleProfileDef',
473
- 'IfcRectangleHollowProfileDef',
474
- 'IfcRoundedRectangleProfileDef',
475
- 'IfcCircleProfileDef',
476
- 'IfcCircleHollowProfileDef',
477
- 'IfcEllipseProfileDef',
478
- 'IfcIShapeProfileDef',
479
- 'IfcAsymmetricIShapeProfileDef',
480
- 'IfcLShapeProfileDef',
481
- 'IfcTShapeProfileDef',
482
- 'IfcUShapeProfileDef',
483
- 'IfcCShapeProfileDef',
484
- 'IfcZShapeProfileDef',
485
- 'IfcTrapeziumProfileDef',
486
- ];
487
- for (const name of parametricProfiles) {
488
- if (schema.entities.find((e) => e.name === name)) {
489
- code += ` Self::${name} => Some(ProfileCategory::Parametric),\n`;
490
- }
491
- }
492
-
493
- code += `
494
- // Arbitrary profiles
495
- `;
496
-
497
- const arbitraryProfiles = [
498
- 'IfcArbitraryClosedProfileDef',
499
- 'IfcArbitraryProfileDefWithVoids',
500
- 'IfcArbitraryOpenProfileDef',
501
- 'IfcCenterLineProfileDef',
502
- ];
503
- for (const name of arbitraryProfiles) {
504
- if (schema.entities.find((e) => e.name === name)) {
505
- code += ` Self::${name} => Some(ProfileCategory::Arbitrary),\n`;
506
- }
507
- }
508
-
509
- code += `
510
- // Composite profiles
511
- `;
512
-
513
- if (schema.entities.find((e) => e.name === 'IfcCompositeProfileDef')) {
514
- code += ` Self::IfcCompositeProfileDef => Some(ProfileCategory::Composite),\n`;
515
- }
516
- if (schema.entities.find((e) => e.name === 'IfcDerivedProfileDef')) {
517
- code += ` Self::IfcDerivedProfileDef => Some(ProfileCategory::Composite),\n`;
518
- }
519
- if (schema.entities.find((e) => e.name === 'IfcMirroredProfileDef')) {
520
- code += ` Self::IfcMirroredProfileDef => Some(ProfileCategory::Composite),\n`;
521
- }
522
-
523
- code += `
524
- _ => None,
525
- }
526
- }
527
-
528
- /// Check if this type is a spatial structure element
529
- pub fn is_spatial(&self) -> bool {
530
- matches!(
531
- self,
532
- `;
533
-
534
- const spatialEntities = [
535
- 'IfcProject',
536
- 'IfcSite',
537
- 'IfcBuilding',
538
- 'IfcBuildingStorey',
539
- 'IfcSpace',
540
- 'IfcFacility',
541
- 'IfcFacilityPart',
542
- ];
543
- const validSpatial = spatialEntities.filter((n) => schema.entities.find((e) => e.name === n));
544
- if (validSpatial.length > 0) {
545
- code += ` ${validSpatial.map((n) => `Self::${n}`).join('\n | ')}\n`;
546
- } else {
547
- code += ` Self::Unknown(_) // No spatial types found\n`;
548
- }
549
-
550
- code += ` )
551
- }
552
-
553
- /// Check if this type can have geometry
554
- pub fn can_have_geometry(&self) -> bool {
555
- // Products can have geometry through representations
556
- self.is_product() && !self.is_spatial()
557
- }
558
-
559
- /// Check if this type is a product (can have placement/representation)
560
- pub fn is_product(&self) -> bool {
561
- // Check if it's a subtype of IfcProduct
562
- self.is_subtype_of(Self::IfcProduct) || *self == Self::IfcProduct
563
- }
564
-
565
- /// Check if this type is a relationship
566
- pub fn is_relationship(&self) -> bool {
567
- // Check if name starts with IfcRel
568
- self.name().starts_with("IfcRel")
569
- }
570
-
571
- /// Check if this is a building element
572
- pub fn is_building_element(&self) -> bool {
573
- let name = self.name();
574
- matches!(
575
- *self,
576
- Self::IfcWall | Self::IfcWallStandardCase | Self::IfcSlab |
577
- Self::IfcBeam | Self::IfcColumn | Self::IfcRoof |
578
- Self::IfcStair | Self::IfcRamp | Self::IfcRailing |
579
- Self::IfcPlate | Self::IfcMember | Self::IfcFooting |
580
- Self::IfcPile | Self::IfcCovering | Self::IfcCurtainWall |
581
- Self::IfcDoor | Self::IfcWindow | Self::IfcChimney |
582
- Self::IfcShadingDevice | Self::IfcBuildingElementProxy |
583
- Self::IfcBuildingElementPart
584
- ) || name.contains("Reinforc")
585
- }
586
- }
587
- `;
588
-
589
- return code;
590
- }
591
-
592
- /**
593
- * Categorize entities for organized output
594
- */
595
- function categorizeEntities(
596
- schema: ExpressSchema
597
- ): Record<string, EntityDefinition[]> {
598
- const categories: Record<string, EntityDefinition[]> = {
599
- 'Spatial Structure': [],
600
- 'Building Elements': [],
601
- Openings: [],
602
- MEP: [],
603
- 'Geometry Representations': [],
604
- 'Geometry Primitives': [],
605
- Profiles: [],
606
- Curves: [],
607
- Surfaces: [],
608
- Relationships: [],
609
- Properties: [],
610
- Materials: [],
611
- 'Presentation & Style': [],
612
- 'Core & Common': [],
613
- Other: [],
614
- };
615
-
616
- for (const entity of schema.entities) {
617
- const name = entity.name;
618
- const chain = getInheritanceChain(entity, schema);
619
-
620
- if (
621
- name.includes('Site') ||
622
- name.includes('Building') ||
623
- name.includes('Storey') ||
624
- name.includes('Space') ||
625
- name.includes('Project') ||
626
- chain.includes('IfcSpatialStructureElement')
627
- ) {
628
- categories['Spatial Structure'].push(entity);
629
- } else if (
630
- chain.includes('IfcBuildingElement') ||
631
- name.includes('Wall') ||
632
- name.includes('Slab') ||
633
- name.includes('Beam') ||
634
- name.includes('Column')
635
- ) {
636
- categories['Building Elements'].push(entity);
637
- } else if (
638
- name.includes('Door') ||
639
- name.includes('Window') ||
640
- name.includes('Opening')
641
- ) {
642
- categories['Openings'].push(entity);
643
- } else if (
644
- name.includes('Pipe') ||
645
- name.includes('Duct') ||
646
- name.includes('Cable') ||
647
- chain.includes('IfcDistributionElement')
648
- ) {
649
- categories['MEP'].push(entity);
650
- } else if (
651
- name.includes('Representation') ||
652
- name.includes('Shape') ||
653
- name.includes('GeometricSet')
654
- ) {
655
- categories['Geometry Representations'].push(entity);
656
- } else if (
657
- name.includes('Solid') ||
658
- name.includes('Brep') ||
659
- name.includes('Boolean') ||
660
- name.includes('Csg') ||
661
- name.includes('FaceSet')
662
- ) {
663
- categories['Geometry Primitives'].push(entity);
664
- } else if (name.includes('Profile')) {
665
- categories['Profiles'].push(entity);
666
- } else if (
667
- name.includes('Curve') ||
668
- name.includes('Polyline') ||
669
- name.includes('Circle') ||
670
- name.includes('Ellipse') ||
671
- name.includes('Line') ||
672
- name.includes('Spline')
673
- ) {
674
- categories['Curves'].push(entity);
675
- } else if (name.includes('Surface') || name.includes('Plane')) {
676
- categories['Surfaces'].push(entity);
677
- } else if (name.startsWith('IfcRel')) {
678
- categories['Relationships'].push(entity);
679
- } else if (
680
- name.includes('Property') ||
681
- name.includes('Quantity') ||
682
- name.includes('Value')
683
- ) {
684
- categories['Properties'].push(entity);
685
- } else if (name.includes('Material')) {
686
- categories['Materials'].push(entity);
687
- } else if (
688
- name.includes('Style') ||
689
- name.includes('Colour') ||
690
- name.includes('Presentation')
691
- ) {
692
- categories['Presentation & Style'].push(entity);
693
- } else if (
694
- name.includes('Root') ||
695
- name.includes('Object') ||
696
- name.includes('Product') ||
697
- name.includes('Element') ||
698
- name.includes('Resource')
699
- ) {
700
- categories['Core & Common'].push(entity);
701
- } else {
702
- categories['Other'].push(entity);
703
- }
704
- }
705
-
706
- // Remove empty categories
707
- for (const key of Object.keys(categories)) {
708
- if (categories[key].length === 0) {
709
- delete categories[key];
710
- }
711
- }
712
-
713
- return categories;
714
- }