@ifc-lite/codegen 1.15.4 → 1.15.5
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 +17 -14
- package/package.json +16 -6
- package/.turbo/turbo-build.log +0 -4
- package/CHANGELOG.md +0 -165
- package/INTEGRATION.md +0 -360
- package/generated/ifc4/entities.ts +0 -7400
- package/generated/ifc4/enums.ts +0 -2467
- package/generated/ifc4/index.ts +0 -17
- package/generated/ifc4/schema-registry.ts +0 -63186
- package/generated/ifc4/selects.ts +0 -315
- package/generated/ifc4/serializers.ts +0 -51
- package/generated/ifc4/test-compile.ts +0 -49
- package/generated/ifc4/type-ids.ts +0 -1682
- package/generated/ifc4/types.ts +0 -401
- package/generated/ifc4x3/entities.ts +0 -8300
- package/generated/ifc4x3/enums.ts +0 -3096
- package/generated/ifc4x3/index.ts +0 -17
- package/generated/ifc4x3/schema-registry.ts +0 -71489
- package/generated/ifc4x3/selects.ts +0 -312
- package/generated/ifc4x3/serializers.ts +0 -51
- package/generated/ifc4x3/test-compile.ts +0 -49
- package/generated/ifc4x3/type-ids.ts +0 -1882
- package/generated/ifc4x3/types.ts +0 -407
- package/src/cli.ts +0 -72
- package/src/crc32.ts +0 -77
- package/src/express-parser.ts +0 -457
- package/src/generator.ts +0 -268
- package/src/index.ts +0 -57
- package/src/rust-generator.ts +0 -714
- package/src/serialization-generator.ts +0 -74
- package/src/type-ids-generator.ts +0 -166
- package/src/typescript-generator.ts +0 -631
- package/test/express-parser.test.ts +0 -363
- package/test/integration.test.ts +0 -246
- package/test/serialization-generator.test.ts +0 -65
- package/test/typescript-generator.test.ts +0 -348
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -18
package/README.md
CHANGED
|
@@ -14,19 +14,25 @@ npm install --save-dev @ifc-lite/codegen
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
# IFC4 (776 entities)
|
|
17
|
-
|
|
17
|
+
node dist/cli.js schemas/IFC4_ADD2_TC1.exp --output ./generated/ifc4
|
|
18
18
|
|
|
19
19
|
# IFC4X3 (876 entities, includes infrastructure: roads, bridges, alignments)
|
|
20
|
-
|
|
20
|
+
node dist/cli.js schemas/IFC4X3.exp --output ./generated/ifc4x3
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
Pass `--rust` to also emit Rust type tables (consumed by the ifc-lite Rust core).
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
Generated files (one per output directory, e.g. `./generated/ifc4`):
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
generated/ifc4/
|
|
27
29
|
├── entities.ts ← TypeScript interfaces for every entity
|
|
30
|
+
├── types.ts ← defined-type aliases
|
|
31
|
+
├── enums.ts ← enum definitions
|
|
32
|
+
├── selects.ts ← SELECT union types
|
|
28
33
|
├── schema-registry.ts ← runtime metadata (parent, attributes, ...)
|
|
29
|
-
├──
|
|
34
|
+
├── type-ids.ts ← numeric type-id lookup tables
|
|
35
|
+
├── serializers.ts ← STEP serializer bound to the schema registry
|
|
30
36
|
└── index.ts ← barrel export
|
|
31
37
|
```
|
|
32
38
|
|
|
@@ -34,19 +40,16 @@ src/generated/
|
|
|
34
40
|
|
|
35
41
|
```typescript
|
|
36
42
|
import { parseExpressSchema, generateTypeScript } from '@ifc-lite/codegen';
|
|
37
|
-
import { writeFile } from 'node:fs/promises';
|
|
43
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
38
44
|
|
|
39
|
-
const schema = parseExpressSchema('./schemas/IFC4.exp');
|
|
45
|
+
const schema = parseExpressSchema(await readFile('./schemas/IFC4.exp', 'utf-8'));
|
|
40
46
|
|
|
41
47
|
console.log(`Parsed ${schema.entities.length} entities, ${schema.types.length} types`);
|
|
42
48
|
|
|
43
|
-
const generated = generateTypeScript(schema
|
|
44
|
-
inheritanceChain: true,
|
|
45
|
-
emitEnums: true,
|
|
46
|
-
});
|
|
49
|
+
const generated = generateTypeScript(schema);
|
|
47
50
|
|
|
48
|
-
await writeFile('./
|
|
49
|
-
await writeFile('./
|
|
51
|
+
await writeFile('./generated/ifc4/entities.ts', generated.entities);
|
|
52
|
+
await writeFile('./generated/ifc4/schema-registry.ts', generated.schemaRegistry);
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
## What you get
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/codegen",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.5",
|
|
4
4
|
"description": "TypeScript code generator from IFC EXPRESS schemas",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -16,17 +16,27 @@
|
|
|
16
16
|
"codegen",
|
|
17
17
|
"typescript"
|
|
18
18
|
],
|
|
19
|
-
"author": "",
|
|
20
|
-
"license": "
|
|
19
|
+
"author": "Louis True",
|
|
20
|
+
"license": "MPL-2.0",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"commander": "^15.0.0",
|
|
23
|
-
"@ifc-lite/data": "^2.1
|
|
23
|
+
"@ifc-lite/data": "^2.5.1"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@types/node": "^
|
|
26
|
+
"@types/node": "^26.1.0",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
|
-
"vitest": "^4.1.
|
|
28
|
+
"vitest": "^4.1.9"
|
|
29
29
|
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://ltplus-ag.github.io/ifc-lite/",
|
|
34
|
+
"bugs": "https://github.com/LTplus-AG/ifc-lite/issues",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"schemas",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
30
40
|
"scripts": {
|
|
31
41
|
"build": "pnpm exec tsc",
|
|
32
42
|
"dev": "pnpm exec tsc --watch",
|
package/.turbo/turbo-build.log
DELETED
package/CHANGELOG.md
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# @ifc-lite/codegen
|
|
2
|
-
|
|
3
|
-
## 1.15.4
|
|
4
|
-
|
|
5
|
-
### Patch Changes
|
|
6
|
-
|
|
7
|
-
- [#1151](https://github.com/LTplus-AG/ifc-lite/pull/1151) [`bfd9004`](https://github.com/LTplus-AG/ifc-lite/commit/bfd9004daa17f481a7b33b5c3c11f620e6cd894d) Thanks [@louistrue](https://github.com/louistrue)! - De-duplicate the STEP serializer into a single source of truth. The
|
|
8
|
-
schema-agnostic STEP serialization logic (`serializeValue`, `generateHeader`,
|
|
9
|
-
`parseStepValue`, `ref`/`enumVal`/`isEntityRef`/`isEnumValue`, and the
|
|
10
|
-
registry-injected `toStepLineWithRegistry` / `generateStepFileWithRegistry`)
|
|
11
|
-
previously existed as four hand-synced copies — the codegen template plus three
|
|
12
|
-
generated `serializers.ts` files — which had already silently drifted (the
|
|
13
|
-
runtime copy carried a `?? []` hardening the template lacked). It now lives once
|
|
14
|
-
in `@ifc-lite/data`; the per-schema bundles (parser runtime + codegen outputs)
|
|
15
|
-
are thin re-exports that only bind their own `SCHEMA_REGISTRY` to the
|
|
16
|
-
registry-coupled helpers, so the copies can never diverge again. A codegen test
|
|
17
|
-
asserts the generated bundle stays a thin re-export rather than re-inlining
|
|
18
|
-
logic.
|
|
19
|
-
|
|
20
|
-
Also fixes the broken `generate:ifc4` script (it pointed at a non-existent
|
|
21
|
-
`schemas/IFC4.exp`; the real file is `schemas/IFC4_ADD2_TC1.exp`). No public
|
|
22
|
-
behaviour change: `@ifc-lite/parser` re-exports the same serializer symbols as
|
|
23
|
-
before; `@ifc-lite/data` gains the shared primitives; `@ifc-lite/codegen` now
|
|
24
|
-
declares `@ifc-lite/data` as a dependency since the generated bundle imports it.
|
|
25
|
-
|
|
26
|
-
- [#1143](https://github.com/LTplus-AG/ifc-lite/pull/1143) [`248f2c0`](https://github.com/LTplus-AG/ifc-lite/commit/248f2c09a4d61fa27dfeaba5511a2a641d4cd278) Thanks [@louistrue](https://github.com/louistrue)! - Preserve source IFC HEADER fields on round-trip export. Re-exporting an
|
|
27
|
-
imported file previously regenerated a fresh ifc-lite header, silently dropping
|
|
28
|
-
the source `FILE_DESCRIPTION` items (any `ViewDefinition [...]` label and vendor
|
|
29
|
-
identifier / coordinate-reference strings) and flattening the exact
|
|
30
|
-
`FILE_SCHEMA` token (e.g. `IFC4X3_ADD2` → `IFC4X3`, which some toolchains
|
|
31
|
-
reject).
|
|
32
|
-
|
|
33
|
-
The parser now captures the verbatim HEADER onto a new
|
|
34
|
-
`IfcDataStore.sourceHeader` (`IfcSourceHeader`, exported from `@ifc-lite/data`;
|
|
35
|
-
parser also exports `parseSourceHeader`), threaded through the worker transport.
|
|
36
|
-
`StepExporter` reproduces the source `FILE_DESCRIPTION` items and the exact
|
|
37
|
-
`FILE_SCHEMA` token when not converting schemas, falling back to parsing the
|
|
38
|
-
source bytes for cache-restored stores. Provenance stays honest:
|
|
39
|
-
`preprocessor_version` is set to `ifc-lite` while the source authoring tool is
|
|
40
|
-
kept as `originating_system`, and when mutations exist exactly one
|
|
41
|
-
`Re-exported by ifc-lite, N modification(s)` item is appended without removing
|
|
42
|
-
the source items. `generateHeader` now accepts description/author/organization
|
|
43
|
-
arrays plus a free-form schema token and STEP-escapes all fields; it also emits
|
|
44
|
-
a properly parenthesised `FILE_DESCRIPTION` list (the prior single-string form
|
|
45
|
-
was malformed STEP). Created-from-scratch (`IfcCreator`) and federated/merged
|
|
46
|
-
exports are unaffected — they keep their own provenance headers by design.
|
|
47
|
-
|
|
48
|
-
- Updated dependencies [[`bfd9004`](https://github.com/LTplus-AG/ifc-lite/commit/bfd9004daa17f481a7b33b5c3c11f620e6cd894d), [`248f2c0`](https://github.com/LTplus-AG/ifc-lite/commit/248f2c09a4d61fa27dfeaba5511a2a641d4cd278), [`ddae2b0`](https://github.com/LTplus-AG/ifc-lite/commit/ddae2b0024f071d00f9e6e4b77e0be3965412ec3)]:
|
|
49
|
-
- @ifc-lite/data@2.1.0
|
|
50
|
-
|
|
51
|
-
## 1.15.3
|
|
52
|
-
|
|
53
|
-
### Patch Changes
|
|
54
|
-
|
|
55
|
-
- [#946](https://github.com/LTplus-AG/ifc-lite/pull/946) [`6378998`](https://github.com/LTplus-AG/ifc-lite/commit/6378998ec146f7f9297ef5fcc5953b155fd6b5e0) Thanks [@louistrue](https://github.com/louistrue)! - Fix a batch of verified findings from a full-codebase review (security, correctness,
|
|
56
|
-
data-loss, and resource/memory leaks). Highlights:
|
|
57
|
-
|
|
58
|
-
**Security**
|
|
59
|
-
|
|
60
|
-
- collab-server: a malformed WebSocket frame no longer crashes the whole process
|
|
61
|
-
(decode is wrapped; a bad frame is rejected/audited instead of throwing).
|
|
62
|
-
- mcp: the local HTTP transport now validates `Host`/`Origin` and no longer sends a
|
|
63
|
-
wildcard `Access-Control-Allow-Origin`, closing a DNS-rebinding/CSRF hole; the
|
|
64
|
-
`AuthScope.modelIds` allowlist is now enforced at model resolution.
|
|
65
|
-
- server-bin: `extractZip` uses `execFileSync` (argv, no shell), removing command
|
|
66
|
-
injection via archive/destination paths.
|
|
67
|
-
- export / sdk / cli / mcp / lists / viewer CSV exporters now neutralize spreadsheet
|
|
68
|
-
formula injection (CWE-1236) consistently.
|
|
69
|
-
- create-ifc-lite: validates the project name (no path traversal) and drops the
|
|
70
|
-
unused `execSync`-based downloader.
|
|
71
|
-
- embed-sdk: inbound `postMessage` now validates `event.origin`.
|
|
72
|
-
|
|
73
|
-
**Correctness / data-loss**
|
|
74
|
-
|
|
75
|
-
- parser: `lengthUnitScale` survives the worker transport; the nested STEP list
|
|
76
|
-
parser is string-aware (commas/parens inside quoted values no longer mis-split).
|
|
77
|
-
- mutations: deleting a property from a session-created pset and replaying
|
|
78
|
-
`UPDATE_ATTRIBUTE` / `CREATE_PROPERTY_SET` mutations now work.
|
|
79
|
-
- export: merged-export ID remapping no longer rewrites `#N` inside quoted strings.
|
|
80
|
-
- drawing-2d: GPU section cutter triangle upload/readback use correct WGSL std-layout
|
|
81
|
-
offsets and strides.
|
|
82
|
-
- ifcx: cyclic children no longer abort the parse; spatial children round-trip; the
|
|
83
|
-
mesh transform guards a zero/non-finite homogeneous `w`.
|
|
84
|
-
- data / cache: a `NULL` string property value stays `null` instead of becoming `""`.
|
|
85
|
-
- pointcloud, bcf, server-client, query, viewer-core, viewer store/federation: assorted
|
|
86
|
-
decoding, federation-id, and selection-state fixes.
|
|
87
|
-
|
|
88
|
-
**Resource / memory leaks**
|
|
89
|
-
|
|
90
|
-
- geometry, query (DuckDB), renderer (GPU buffers), collab (federation presence),
|
|
91
|
-
sandbox (host log capture + runtime), mcp (clash mesh cache), server-bin (signal
|
|
92
|
-
listeners), and the viewer renderer on unmount now release resources deterministically.
|
|
93
|
-
|
|
94
|
-
**Hardening (apps, not published)**
|
|
95
|
-
|
|
96
|
-
- server: a dedicated `server-release` Cargo profile (`panic = "unwind"`) plus a
|
|
97
|
-
`CatchPanicLayer` contain a malformed-IFC parse panic to the offending request
|
|
98
|
-
instead of aborting the whole server.
|
|
99
|
-
- desktop (Tauri): a Content-Security-Policy is set, and unused `shell:*` /
|
|
100
|
-
`fs:allow-write|mkdir|remove` capabilities (and the unused shell plugin) are removed.
|
|
101
|
-
|
|
102
|
-
**Second pass** (additional verified findings)
|
|
103
|
-
|
|
104
|
-
- collab-server: S3 log load now follows `ListObjectsV2` pagination (no dropped frames);
|
|
105
|
-
awareness frames are size-capped + rate-limited; path-lock verify runs after role/rate-limit;
|
|
106
|
-
the blob route requires auth and `/metrics` can be token-gated.
|
|
107
|
-
- server-bin: downloaded binaries are SHA-256 verified against a release sidecar (fail-closed on
|
|
108
|
-
mismatch, warn-if-absent for older releases).
|
|
109
|
-
- extensions: inner-ring capability check fails _closed_ for unknown namespaces; signing
|
|
110
|
-
canonicalization is now injective (length-prefixed).
|
|
111
|
-
- correctness/leaks: mutations quantity type+unit preserved on replay; `findByProperty` boolean
|
|
112
|
-
comparisons; Parquet REAL columns kept as Float64; blob GC fail-safe on missing `uploadedAt`;
|
|
113
|
-
spatial-hierarchy + codegen cycle guards; BVH NaN edge; bSDD/playground caches bounded;
|
|
114
|
-
point-cloud GPU asset freed on federation error; mcp `parseColor` rejects non-hex; bcf/SVG/STEP
|
|
115
|
-
output escaping; and more.
|
|
116
|
-
|
|
117
|
-
## 1.15.2
|
|
118
|
-
|
|
119
|
-
### Patch Changes
|
|
120
|
-
|
|
121
|
-
- [#494](https://github.com/louistrue/ifc-lite/pull/494) [`ec0d3a0`](https://github.com/louistrue/ifc-lite/commit/ec0d3a0e4c7f9eaeb26ab0a724fd76d955e52ac5) Thanks [@louistrue](https://github.com/louistrue)! - Remove recursive package `prebuild` hooks and run TypeScript via `pnpm exec` so workspace builds resolve correctly on Windows.
|
|
122
|
-
|
|
123
|
-
## 1.15.1
|
|
124
|
-
|
|
125
|
-
### Patch Changes
|
|
126
|
-
|
|
127
|
-
- [#461](https://github.com/louistrue/ifc-lite/pull/461) [`6ce40dd`](https://github.com/louistrue/ifc-lite/commit/6ce40ddb0cace5f83c2438d2d4c4bd47703468f7) Thanks [@louistrue](https://github.com/louistrue)! - Clean up package build health for georeferencing work by fixing parser generation issues, making export tests resolve workspace packages reliably, removing build scripts that masked TypeScript failures, tightening workspace test/build scripts, productizing CLI LOD generation, centralizing IFC GUID utilities in encoding, and adding mutation test coverage for property editing flows.
|
|
128
|
-
|
|
129
|
-
## 1.15.0
|
|
130
|
-
|
|
131
|
-
### Minor Changes
|
|
132
|
-
|
|
133
|
-
- [#354](https://github.com/louistrue/ifc-lite/pull/354) [`3f212f1`](https://github.com/louistrue/ifc-lite/commit/3f212f1e24b896cbc6ff63444c02635a1128ba3f) Thanks [@louistrue](https://github.com/louistrue)! - Replace hardcoded IFC schema with codegen from EXPRESS schema, adding full type entity support (776 entities)
|
|
134
|
-
|
|
135
|
-
## 1.14.3
|
|
136
|
-
|
|
137
|
-
## 1.14.2
|
|
138
|
-
|
|
139
|
-
## 1.14.1
|
|
140
|
-
|
|
141
|
-
## 1.14.0
|
|
142
|
-
|
|
143
|
-
## 1.13.0
|
|
144
|
-
|
|
145
|
-
## 1.12.0
|
|
146
|
-
|
|
147
|
-
## 1.11.3
|
|
148
|
-
|
|
149
|
-
## 1.11.1
|
|
150
|
-
|
|
151
|
-
## 1.11.0
|
|
152
|
-
|
|
153
|
-
## 1.10.0
|
|
154
|
-
|
|
155
|
-
## 1.9.0
|
|
156
|
-
|
|
157
|
-
## 1.8.0
|
|
158
|
-
|
|
159
|
-
## 1.7.0
|
|
160
|
-
|
|
161
|
-
## 1.2.1
|
|
162
|
-
|
|
163
|
-
### Patch Changes
|
|
164
|
-
|
|
165
|
-
- Version sync with @ifc-lite packages
|
package/INTEGRATION.md
DELETED
|
@@ -1,360 +0,0 @@
|
|
|
1
|
-
# Integration Guide: Using Generated IFC Types in Parser
|
|
2
|
-
|
|
3
|
-
This guide explains how to integrate the generated TypeScript code from `@ifc-lite/codegen` into the `@ifc-lite/parser` package.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The codegen package generates 5 TypeScript files from IFC EXPRESS schemas:
|
|
8
|
-
|
|
9
|
-
1. **entities.ts** - Entity interfaces (776 for IFC4, 876 for IFC4X3)
|
|
10
|
-
2. **types.ts** - Type aliases (397 for IFC4, 436 for IFC4X3)
|
|
11
|
-
3. **enums.ts** - Enum definitions (207 for IFC4, 243 for IFC4X3)
|
|
12
|
-
4. **selects.ts** - Union types (60 for IFC4, 61 for IFC4X3)
|
|
13
|
-
5. **schema-registry.ts** - Runtime metadata (1.6 MB for IFC4)
|
|
14
|
-
|
|
15
|
-
Total: ~75K lines of TypeScript covering 100% of the IFC schema.
|
|
16
|
-
|
|
17
|
-
## Benefits
|
|
18
|
-
|
|
19
|
-
### Before (Manual Implementation)
|
|
20
|
-
- ~70 manually implemented entity types
|
|
21
|
-
- ~7% schema coverage
|
|
22
|
-
- Manual updates for new IFC versions
|
|
23
|
-
- No materials, georeferencing, infrastructure
|
|
24
|
-
|
|
25
|
-
### After (Code Generation)
|
|
26
|
-
- 776-876 automatically generated entity types
|
|
27
|
-
- 100% schema coverage
|
|
28
|
-
- Automatic updates (regenerate from .exp files)
|
|
29
|
-
- Full support: materials, georeferencing, roads, bridges, railways
|
|
30
|
-
|
|
31
|
-
## Integration Steps
|
|
32
|
-
|
|
33
|
-
### Step 1: Generate Code
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
cd packages/codegen
|
|
37
|
-
|
|
38
|
-
# Generate IFC4 types
|
|
39
|
-
npm run generate:ifc4
|
|
40
|
-
|
|
41
|
-
# Generate IFC4X3 types (infrastructure support)
|
|
42
|
-
npm run generate:ifc4x3
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Generated files: `packages/codegen/generated/ifc4/` or `generated/ifc4x3/`
|
|
46
|
-
|
|
47
|
-
> **Runtime dependency:** the generated `serializers.ts` is a thin re-export of
|
|
48
|
-
> the schema-agnostic STEP serializer in `@ifc-lite/data` (it only binds the
|
|
49
|
-
> bundle's `SCHEMA_REGISTRY`). Any project that consumes a generated bundle must
|
|
50
|
-
> therefore have `@ifc-lite/data` installed. This keeps the serialization logic
|
|
51
|
-
> in one place so the per-schema copies can never drift.
|
|
52
|
-
|
|
53
|
-
### Step 2: Copy Generated Files to Parser
|
|
54
|
-
|
|
55
|
-
Option A: **Direct Copy** (recommended for testing)
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
# Copy IFC4 generated types to parser
|
|
59
|
-
cp -r packages/codegen/generated/ifc4/* packages/parser/src/schema/
|
|
60
|
-
|
|
61
|
-
# Or IFC4X3
|
|
62
|
-
cp -r packages/codegen/generated/ifc4x3/* packages/parser/src/schema/
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Option B: **Symlink** (for development)
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
ln -s ../../codegen/generated/ifc4 packages/parser/src/schema
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Option C: **npm Package** (for production)
|
|
72
|
-
|
|
73
|
-
Publish `@ifc-lite/ifc4-schema` and import it:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
import { IfcWall, IfcDoor, SCHEMA_REGISTRY } from '@ifc-lite/ifc4-schema';
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Step 3: Update Parser Imports
|
|
80
|
-
|
|
81
|
-
Replace the manual `ifc-schema.ts` with generated types:
|
|
82
|
-
|
|
83
|
-
**Before:**
|
|
84
|
-
```typescript
|
|
85
|
-
// packages/parser/src/ifc-schema.ts
|
|
86
|
-
export const IFC_SCHEMA = {
|
|
87
|
-
IfcWall: {
|
|
88
|
-
parent: 'IfcBuildingElement',
|
|
89
|
-
attributes: ['GlobalId', 'Name', ...],
|
|
90
|
-
},
|
|
91
|
-
// ... only ~70 entities
|
|
92
|
-
};
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**After:**
|
|
96
|
-
```typescript
|
|
97
|
-
// Use generated schema registry
|
|
98
|
-
export { SCHEMA_REGISTRY, getEntityMetadata, getAllAttributesForEntity } from './schema/schema-registry';
|
|
99
|
-
|
|
100
|
-
// Use generated types
|
|
101
|
-
export type { IfcWall, IfcDoor, IfcWindow, IfcProject } from './schema/entities';
|
|
102
|
-
export { IfcWallTypeEnum, IfcDoorTypeEnum } from './schema/enums';
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Step 4: Update Entity Extractor
|
|
106
|
-
|
|
107
|
-
The `entity-extractor.ts` can now use generated types:
|
|
108
|
-
|
|
109
|
-
**Before:**
|
|
110
|
-
```typescript
|
|
111
|
-
// Manual type checking
|
|
112
|
-
if (typeName === 'IfcWall' || typeName === 'IfcDoor') {
|
|
113
|
-
// handle building elements
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
**After:**
|
|
118
|
-
```typescript
|
|
119
|
-
import { getEntityMetadata, isKnownEntity } from './schema/schema-registry';
|
|
120
|
-
|
|
121
|
-
// Schema-driven parsing
|
|
122
|
-
if (isKnownEntity(typeName)) {
|
|
123
|
-
const metadata = getEntityMetadata(typeName);
|
|
124
|
-
const attributes = metadata.allAttributes; // includes inherited!
|
|
125
|
-
|
|
126
|
-
// Parse all attributes dynamically
|
|
127
|
-
for (const attr of attributes) {
|
|
128
|
-
parseAttribute(entity, attr.name, attr.type, attr.optional);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### Step 5: Add Specialized Extractors
|
|
134
|
-
|
|
135
|
-
With 100% schema coverage, you can now add extractors for previously missing concepts:
|
|
136
|
-
|
|
137
|
-
#### Materials Extractor
|
|
138
|
-
|
|
139
|
-
```typescript
|
|
140
|
-
// packages/parser/src/material-extractor.ts
|
|
141
|
-
import type { IfcMaterial, IfcMaterialLayer, IfcMaterialLayerSet } from './schema/entities';
|
|
142
|
-
|
|
143
|
-
export function extractMaterials(entities: Map<number, IfcEntity>): Material[] {
|
|
144
|
-
// Now you have full type definitions for:
|
|
145
|
-
// - IfcMaterial
|
|
146
|
-
// - IfcMaterialLayer
|
|
147
|
-
// - IfcMaterialLayerSet
|
|
148
|
-
// - IfcMaterialProfile
|
|
149
|
-
// - IfcMaterialConstituent
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
#### Georeferencing Extractor
|
|
154
|
-
|
|
155
|
-
```typescript
|
|
156
|
-
// packages/parser/src/georef-extractor.ts
|
|
157
|
-
import type { IfcMapConversion, IfcProjectedCRS } from './schema/entities';
|
|
158
|
-
|
|
159
|
-
export function extractGeoreferencing(project: IfcProject): GeoreferenceInfo {
|
|
160
|
-
// Parse IfcMapConversion and IfcProjectedCRS
|
|
161
|
-
// Transform coordinates to target CRS
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
#### Infrastructure Support (IFC4X3)
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
// packages/parser/src/infrastructure-extractor.ts
|
|
169
|
-
import type { IfcRoad, IfcBridge, IfcRailway, IfcAlignment } from './schema/entities';
|
|
170
|
-
|
|
171
|
-
export function extractInfrastructure(entities: Map<number, IfcEntity>) {
|
|
172
|
-
// Support for civil infrastructure:
|
|
173
|
-
// - Roads, bridges, railways, tunnels
|
|
174
|
-
// - Alignments and curve segments
|
|
175
|
-
// - Earthworks
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Step 6: Update Tests
|
|
180
|
-
|
|
181
|
-
Update parser tests to use generated types:
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
import { IfcWall, IfcDoor } from './schema/entities';
|
|
185
|
-
import { SCHEMA_REGISTRY } from './schema/schema-registry';
|
|
186
|
-
|
|
187
|
-
describe('Entity parsing', () => {
|
|
188
|
-
it('should parse IfcWall with all attributes', () => {
|
|
189
|
-
const metadata = SCHEMA_REGISTRY.entities.IfcWall;
|
|
190
|
-
|
|
191
|
-
expect(metadata.parent).toBe('IfcBuildingElement');
|
|
192
|
-
expect(metadata.attributes).toHaveLength(1);
|
|
193
|
-
expect(metadata.allAttributes).toHaveLength(14); // Including inherited!
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Usage Examples
|
|
199
|
-
|
|
200
|
-
### Type-Safe Entity Access
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
import type { IfcWall, IfcDoor, IfcWindow } from './schema/entities';
|
|
204
|
-
import { IfcWallTypeEnum } from './schema/enums';
|
|
205
|
-
|
|
206
|
-
// Type-safe entity access
|
|
207
|
-
const wall: IfcWall = {
|
|
208
|
-
GlobalId: '2X3v_TggD0W8N...',
|
|
209
|
-
Name: 'Exterior Wall',
|
|
210
|
-
ObjectType: 'External',
|
|
211
|
-
PredefinedType: IfcWallTypeEnum.SOLIDWALL,
|
|
212
|
-
// TypeScript ensures all required fields are present!
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
// Autocomplete for attributes
|
|
216
|
-
console.log(wall.PredefinedType); // TypeScript knows this exists
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### Schema-Driven Parsing
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
import { getEntityMetadata, getAllAttributesForEntity } from './schema/schema-registry';
|
|
223
|
-
|
|
224
|
-
// Get metadata for any entity
|
|
225
|
-
const wallMeta = getEntityMetadata('IfcWall');
|
|
226
|
-
|
|
227
|
-
console.log(wallMeta.parent); // 'IfcBuildingElement'
|
|
228
|
-
console.log(wallMeta.attributes); // Own attributes
|
|
229
|
-
console.log(wallMeta.allAttributes); // Including inherited
|
|
230
|
-
console.log(wallMeta.inheritanceChain); // ['IfcRoot', 'IfcObject', ...]
|
|
231
|
-
|
|
232
|
-
// Parse attributes dynamically
|
|
233
|
-
for (const attr of wallMeta.allAttributes) {
|
|
234
|
-
if (attr.optional) {
|
|
235
|
-
// Handle optional attribute
|
|
236
|
-
}
|
|
237
|
-
if (attr.isList) {
|
|
238
|
-
// Handle list/array
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### Inheritance Navigation
|
|
244
|
-
|
|
245
|
-
```typescript
|
|
246
|
-
import { getInheritanceChainForEntity } from './schema/schema-registry';
|
|
247
|
-
|
|
248
|
-
// Get full inheritance chain
|
|
249
|
-
const chain = getInheritanceChainForEntity('IfcWall');
|
|
250
|
-
// ['IfcRoot', 'IfcObjectDefinition', 'IfcObject', 'IfcProduct',
|
|
251
|
-
// 'IfcElement', 'IfcBuildingElement', 'IfcWall']
|
|
252
|
-
|
|
253
|
-
// Walk up the chain to get parent attributes
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
## Performance Considerations
|
|
257
|
-
|
|
258
|
-
### Bundle Size
|
|
259
|
-
|
|
260
|
-
| Component | Size | Notes |
|
|
261
|
-
|-----------|------|-------|
|
|
262
|
-
| entities.ts | 149 KB | Entity interfaces |
|
|
263
|
-
| types.ts | 61 KB | Type aliases |
|
|
264
|
-
| enums.ts | 65 KB | Enum definitions |
|
|
265
|
-
| selects.ts | 8 KB | Union types |
|
|
266
|
-
| schema-registry.ts | 1.6 MB | Runtime metadata |
|
|
267
|
-
| **Total** | **~1.9 MB** | Uncompressed |
|
|
268
|
-
|
|
269
|
-
**Mitigation:**
|
|
270
|
-
- Tree-shaking removes unused entities
|
|
271
|
-
- gzip compression: ~1.9 MB → ~200 KB
|
|
272
|
-
- Lazy load schema-registry only when needed
|
|
273
|
-
- Split by IFC version (load IFC4 OR IFC4X3, not both)
|
|
274
|
-
|
|
275
|
-
### Parse Performance
|
|
276
|
-
|
|
277
|
-
Generated code has **minimal performance impact**:
|
|
278
|
-
- Entity extraction remains byte-level scanning (fast)
|
|
279
|
-
- Schema lookups are O(1) (hash maps)
|
|
280
|
-
- No regex compilation overhead
|
|
281
|
-
- Columnar storage unchanged
|
|
282
|
-
|
|
283
|
-
Benchmark: Parsing a 50 MB IFC file
|
|
284
|
-
- Before: ~2.5s
|
|
285
|
-
- After: ~2.6s (4% slower, but 100% coverage vs 7%)
|
|
286
|
-
|
|
287
|
-
## Migration Checklist
|
|
288
|
-
|
|
289
|
-
- [ ] Generate types from IFC4 schema
|
|
290
|
-
- [ ] Copy generated files to parser/src/schema/
|
|
291
|
-
- [ ] Update imports in entity-extractor.ts
|
|
292
|
-
- [ ] Replace manual ifc-schema.ts with SCHEMA_REGISTRY
|
|
293
|
-
- [ ] Update property-extractor.ts to use schema metadata
|
|
294
|
-
- [ ] Add material-extractor.ts (now possible!)
|
|
295
|
-
- [ ] Add georef-extractor.ts (now possible!)
|
|
296
|
-
- [ ] Update tests to use generated types
|
|
297
|
-
- [ ] Run full test suite
|
|
298
|
-
- [ ] Test with real IFC files
|
|
299
|
-
- [ ] Measure bundle size impact
|
|
300
|
-
- [ ] Optimize with tree-shaking if needed
|
|
301
|
-
|
|
302
|
-
## Regenerating Types
|
|
303
|
-
|
|
304
|
-
When IFC schemas are updated:
|
|
305
|
-
|
|
306
|
-
```bash
|
|
307
|
-
# Download new schema from buildingSMART
|
|
308
|
-
curl -o packages/codegen/schemas/IFC4_ADD3.exp https://...
|
|
309
|
-
|
|
310
|
-
# Regenerate types
|
|
311
|
-
cd packages/codegen
|
|
312
|
-
npm run generate -- schemas/IFC4_ADD3.exp -o generated/ifc4_add3
|
|
313
|
-
|
|
314
|
-
# Copy to parser
|
|
315
|
-
cp -r generated/ifc4_add3/* ../parser/src/schema/
|
|
316
|
-
|
|
317
|
-
# Test
|
|
318
|
-
cd ../parser
|
|
319
|
-
npm test
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## Troubleshooting
|
|
323
|
-
|
|
324
|
-
### "Cannot find name 'IfcXxx'"
|
|
325
|
-
|
|
326
|
-
**Solution:** Import from the correct file:
|
|
327
|
-
```typescript
|
|
328
|
-
import type { IfcWall } from './schema/entities'; // Entity
|
|
329
|
-
import { IfcWallTypeEnum } from './schema/enums'; // Enum
|
|
330
|
-
import type { IfcLabel } from './schema/types'; // Type alias
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
### "Type 'X' is not assignable to type 'Y'"
|
|
334
|
-
|
|
335
|
-
**Solution:** The generated types are strict. Use type assertions carefully:
|
|
336
|
-
```typescript
|
|
337
|
-
const type = entity.attributes[0] as IfcLabel;
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### Bundle size too large
|
|
341
|
-
|
|
342
|
-
**Solution:**
|
|
343
|
-
1. Enable tree-shaking in your bundler
|
|
344
|
-
2. Lazy load schema-registry:
|
|
345
|
-
```typescript
|
|
346
|
-
const { SCHEMA_REGISTRY } = await import('./schema/schema-registry');
|
|
347
|
-
```
|
|
348
|
-
3. Split by IFC version (don't load both IFC4 and IFC4X3)
|
|
349
|
-
|
|
350
|
-
## Next Steps
|
|
351
|
-
|
|
352
|
-
1. **Test extensively** with real IFC files
|
|
353
|
-
2. **Benchmark** performance impact
|
|
354
|
-
3. **Implement specialized extractors** (materials, georeferencing)
|
|
355
|
-
4. **Consider infrastructure support** (IFC4X3 for roads, bridges)
|
|
356
|
-
5. **Optimize bundle size** if needed
|
|
357
|
-
|
|
358
|
-
## Questions?
|
|
359
|
-
|
|
360
|
-
See the main README in `packages/codegen/README.md` for more details.
|