@ifc-lite/ifcx 1.2.1 → 1.3.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/dist/federated-composition.d.ts +69 -0
- package/dist/federated-composition.d.ts.map +1 -0
- package/dist/federated-composition.js +300 -0
- package/dist/federated-composition.js.map +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +168 -0
- package/dist/index.js.map +1 -1
- package/dist/layer-stack.d.ts +151 -0
- package/dist/layer-stack.d.ts.map +1 -0
- package/dist/layer-stack.js +248 -0
- package/dist/layer-stack.js.map +1 -0
- package/dist/path-resolver.d.ts +113 -0
- package/dist/path-resolver.d.ts.map +1 -0
- package/dist/path-resolver.js +211 -0
- package/dist/path-resolver.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federated Composition Engine for IFCX
|
|
3
|
+
*
|
|
4
|
+
* Composes multiple IFCX files (layers) into a unified stage using
|
|
5
|
+
* USD-inspired layer semantics:
|
|
6
|
+
* - Higher layers (lower index) have stronger opinions
|
|
7
|
+
* - Attributes merge with strongest layer winning
|
|
8
|
+
* - Children accumulate across layers
|
|
9
|
+
* - null values remove attributes/children
|
|
10
|
+
* - Inheritance is resolved across layer boundaries
|
|
11
|
+
*/
|
|
12
|
+
import type { IfcxFile, ComposedNode } from './types.js';
|
|
13
|
+
import { LayerStack } from './layer-stack.js';
|
|
14
|
+
import { PathIndex } from './path-resolver.js';
|
|
15
|
+
/**
|
|
16
|
+
* Options for federated composition.
|
|
17
|
+
*/
|
|
18
|
+
export interface ComposeOptions {
|
|
19
|
+
/** Progress callback */
|
|
20
|
+
onProgress?: (phase: string, percent: number) => void;
|
|
21
|
+
/** Maximum inheritance depth (default: 10) */
|
|
22
|
+
maxInheritDepth?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Extended ComposedNode with source tracking.
|
|
26
|
+
*/
|
|
27
|
+
export interface ComposedNodeWithSources extends ComposedNode {
|
|
28
|
+
/** Track which layer contributed each attribute */
|
|
29
|
+
attributeSources: Map<string, {
|
|
30
|
+
layerId: string;
|
|
31
|
+
layerName: string;
|
|
32
|
+
}>;
|
|
33
|
+
/** All layers that contributed to this node */
|
|
34
|
+
contributingLayers: Set<string>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Result of federated composition.
|
|
38
|
+
*/
|
|
39
|
+
export interface FederatedCompositionResult {
|
|
40
|
+
/** Composed nodes by path */
|
|
41
|
+
composed: Map<string, ComposedNodeWithSources>;
|
|
42
|
+
/** Path index for lookups */
|
|
43
|
+
pathIndex: PathIndex;
|
|
44
|
+
/** Root nodes (no parent) */
|
|
45
|
+
roots: ComposedNodeWithSources[];
|
|
46
|
+
/** Statistics */
|
|
47
|
+
stats: {
|
|
48
|
+
totalNodes: number;
|
|
49
|
+
layersUsed: number;
|
|
50
|
+
inheritanceResolutions: number;
|
|
51
|
+
crossLayerReferences: number;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compose multiple IFCX layers into a unified stage.
|
|
56
|
+
*
|
|
57
|
+
* Algorithm:
|
|
58
|
+
* 1. Build path index across all layers
|
|
59
|
+
* 2. Collect all unique paths
|
|
60
|
+
* 3. For each path, merge nodes from all layers (strongest first)
|
|
61
|
+
* 4. Resolve inheritance references (may cross layers)
|
|
62
|
+
* 5. Build parent-child tree from children references
|
|
63
|
+
*/
|
|
64
|
+
export declare function composeFederated(layerStack: LayerStack, options?: ComposeOptions): FederatedCompositionResult;
|
|
65
|
+
/**
|
|
66
|
+
* Compose a single IFCX file (convenience wrapper).
|
|
67
|
+
*/
|
|
68
|
+
export declare function composeSingleFile(file: IfcxFile): FederatedCompositionResult;
|
|
69
|
+
//# sourceMappingURL=federated-composition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federated-composition.d.ts","sourceRoot":"","sources":["../src/federated-composition.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAY,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAa,MAAM,oBAAoB,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wBAAwB;IACxB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,8CAA8C;IAC9C,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAgBD;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,YAAY;IAC3D,mDAAmD;IACnD,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,+CAA+C;IAC/C,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,6BAA6B;IAC7B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IAC/C,6BAA6B;IAC7B,SAAS,EAAE,SAAS,CAAC;IACrB,6BAA6B;IAC7B,KAAK,EAAE,uBAAuB,EAAE,CAAC;IACjC,iBAAiB;IACjB,KAAK,EAAE;QACL,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,oBAAoB,EAAE,MAAM,CAAC;KAC9B,CAAC;CACH;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,cAAmB,GAC3B,0BAA0B,CAiG5B;AAmQD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,0BAA0B,CAI5E"}
|
|
@@ -0,0 +1,300 @@
|
|
|
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
|
+
import { LayerStack } from './layer-stack.js';
|
|
5
|
+
import { PathIndex } from './path-resolver.js';
|
|
6
|
+
/**
|
|
7
|
+
* Compose multiple IFCX layers into a unified stage.
|
|
8
|
+
*
|
|
9
|
+
* Algorithm:
|
|
10
|
+
* 1. Build path index across all layers
|
|
11
|
+
* 2. Collect all unique paths
|
|
12
|
+
* 3. For each path, merge nodes from all layers (strongest first)
|
|
13
|
+
* 4. Resolve inheritance references (may cross layers)
|
|
14
|
+
* 5. Build parent-child tree from children references
|
|
15
|
+
*/
|
|
16
|
+
export function composeFederated(layerStack, options = {}) {
|
|
17
|
+
const { onProgress, maxInheritDepth = 10 } = options;
|
|
18
|
+
onProgress?.('indexing', 0);
|
|
19
|
+
// Get enabled layers in strength order
|
|
20
|
+
const layers = layerStack.getEnabledLayers();
|
|
21
|
+
if (layers.length === 0) {
|
|
22
|
+
return {
|
|
23
|
+
composed: new Map(),
|
|
24
|
+
pathIndex: new PathIndex(),
|
|
25
|
+
roots: [],
|
|
26
|
+
stats: {
|
|
27
|
+
totalNodes: 0,
|
|
28
|
+
layersUsed: 0,
|
|
29
|
+
inheritanceResolutions: 0,
|
|
30
|
+
crossLayerReferences: 0,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// Build path index
|
|
35
|
+
const pathIndex = new PathIndex();
|
|
36
|
+
pathIndex.buildIndex(layers);
|
|
37
|
+
onProgress?.('indexing', 100);
|
|
38
|
+
onProgress?.('merging', 0);
|
|
39
|
+
// Phase 1: Collect and merge all nodes by path
|
|
40
|
+
const preComposed = new Map();
|
|
41
|
+
const allPaths = layerStack.getAllPaths();
|
|
42
|
+
let pathCount = 0;
|
|
43
|
+
const totalPaths = allPaths.size;
|
|
44
|
+
for (const path of allPaths) {
|
|
45
|
+
// Skip hierarchical paths - they're references, not definitions
|
|
46
|
+
if (path.includes('/'))
|
|
47
|
+
continue;
|
|
48
|
+
const pre = mergeNodesForPath(path, layers);
|
|
49
|
+
preComposed.set(path, pre);
|
|
50
|
+
pathCount++;
|
|
51
|
+
if (pathCount % 100 === 0) {
|
|
52
|
+
onProgress?.('merging', Math.round((pathCount / totalPaths) * 100));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
onProgress?.('merging', 100);
|
|
56
|
+
onProgress?.('inheritance', 0);
|
|
57
|
+
// Phase 2: Resolve inheritance
|
|
58
|
+
let inheritanceResolutions = 0;
|
|
59
|
+
let crossLayerReferences = 0;
|
|
60
|
+
const visited = new Set();
|
|
61
|
+
for (const [path, pre] of preComposed) {
|
|
62
|
+
const result = resolveInheritance(path, pre, preComposed, pathIndex, visited, new Set(), maxInheritDepth);
|
|
63
|
+
inheritanceResolutions += result.resolutions;
|
|
64
|
+
crossLayerReferences += result.crossLayer;
|
|
65
|
+
}
|
|
66
|
+
onProgress?.('inheritance', 100);
|
|
67
|
+
onProgress?.('tree', 0);
|
|
68
|
+
// Phase 3: Build composed tree
|
|
69
|
+
const composed = new Map();
|
|
70
|
+
for (const [path] of preComposed) {
|
|
71
|
+
if (!composed.has(path)) {
|
|
72
|
+
composeNode(path, preComposed, composed, new Set(), layers, pathIndex);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
onProgress?.('tree', 100);
|
|
76
|
+
// Find roots
|
|
77
|
+
const roots = findRoots(composed);
|
|
78
|
+
return {
|
|
79
|
+
composed,
|
|
80
|
+
pathIndex,
|
|
81
|
+
roots,
|
|
82
|
+
stats: {
|
|
83
|
+
totalNodes: composed.size,
|
|
84
|
+
layersUsed: layers.length,
|
|
85
|
+
inheritanceResolutions,
|
|
86
|
+
crossLayerReferences,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Merge all nodes for a path across layers.
|
|
92
|
+
* Layers are processed in strength order (strongest first).
|
|
93
|
+
*/
|
|
94
|
+
function mergeNodesForPath(path, layers) {
|
|
95
|
+
const result = {
|
|
96
|
+
path,
|
|
97
|
+
children: {},
|
|
98
|
+
inherits: {},
|
|
99
|
+
attributes: {},
|
|
100
|
+
attributeSources: new Map(),
|
|
101
|
+
definedInLayers: new Set(),
|
|
102
|
+
};
|
|
103
|
+
// Process layers in reverse order (weakest first) so stronger layers override
|
|
104
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
105
|
+
const layer = layers[i];
|
|
106
|
+
const nodes = layer.nodesByPath.get(path);
|
|
107
|
+
if (!nodes)
|
|
108
|
+
continue;
|
|
109
|
+
result.definedInLayers.add(layer.id);
|
|
110
|
+
// Process all nodes for this path in this layer
|
|
111
|
+
for (const node of nodes) {
|
|
112
|
+
// Merge children
|
|
113
|
+
if (node.children) {
|
|
114
|
+
for (const [key, value] of Object.entries(node.children)) {
|
|
115
|
+
if (value === null) {
|
|
116
|
+
// null removes the child
|
|
117
|
+
delete result.children[key];
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
result.children[key] = value;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Merge inherits
|
|
125
|
+
if (node.inherits) {
|
|
126
|
+
for (const [key, value] of Object.entries(node.inherits)) {
|
|
127
|
+
if (value === null) {
|
|
128
|
+
delete result.inherits[key];
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
result.inherits[key] = value;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Merge attributes
|
|
136
|
+
if (node.attributes) {
|
|
137
|
+
for (const [key, value] of Object.entries(node.attributes)) {
|
|
138
|
+
result.attributes[key] = value;
|
|
139
|
+
result.attributeSources.set(key, layer.id);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolve inheritance for a pre-composed node.
|
|
148
|
+
*/
|
|
149
|
+
function resolveInheritance(path, pre, allNodes, pathIndex, resolved, visiting, maxDepth, depth = 0) {
|
|
150
|
+
if (resolved.has(path)) {
|
|
151
|
+
return { resolutions: 0, crossLayer: 0 };
|
|
152
|
+
}
|
|
153
|
+
if (visiting.has(path)) {
|
|
154
|
+
// Circular inheritance - skip
|
|
155
|
+
console.warn(`Circular inheritance detected at path: ${path}`);
|
|
156
|
+
return { resolutions: 0, crossLayer: 0 };
|
|
157
|
+
}
|
|
158
|
+
if (depth > maxDepth) {
|
|
159
|
+
console.warn(`Max inheritance depth exceeded at path: ${path}`);
|
|
160
|
+
return { resolutions: 0, crossLayer: 0 };
|
|
161
|
+
}
|
|
162
|
+
visiting.add(path);
|
|
163
|
+
let resolutions = 0;
|
|
164
|
+
let crossLayer = 0;
|
|
165
|
+
// Resolve each inherit reference
|
|
166
|
+
for (const [, inheritPath] of Object.entries(pre.inherits)) {
|
|
167
|
+
if (!inheritPath)
|
|
168
|
+
continue;
|
|
169
|
+
// Try to resolve the path (may be in different layer)
|
|
170
|
+
const resolvedPath = pathIndex.resolvePath(inheritPath);
|
|
171
|
+
if (!resolvedPath)
|
|
172
|
+
continue;
|
|
173
|
+
const inherited = allNodes.get(resolvedPath);
|
|
174
|
+
if (!inherited)
|
|
175
|
+
continue;
|
|
176
|
+
// Check if cross-layer reference
|
|
177
|
+
const inheritedLayers = inherited.definedInLayers;
|
|
178
|
+
const hasCommonLayer = [...pre.definedInLayers].some((l) => inheritedLayers.has(l));
|
|
179
|
+
if (!hasCommonLayer) {
|
|
180
|
+
crossLayer++;
|
|
181
|
+
}
|
|
182
|
+
// Recursively resolve inheritance of the inherited node first
|
|
183
|
+
const subResult = resolveInheritance(resolvedPath, inherited, allNodes, pathIndex, resolved, visiting, maxDepth, depth + 1);
|
|
184
|
+
resolutions += subResult.resolutions;
|
|
185
|
+
crossLayer += subResult.crossLayer;
|
|
186
|
+
// Merge inherited data (inherited values are weaker - don't override existing)
|
|
187
|
+
for (const [key, value] of Object.entries(inherited.attributes)) {
|
|
188
|
+
if (!(key in pre.attributes)) {
|
|
189
|
+
pre.attributes[key] = value;
|
|
190
|
+
// Track source from inherited node
|
|
191
|
+
const inheritedSource = inherited.attributeSources.get(key);
|
|
192
|
+
if (inheritedSource) {
|
|
193
|
+
pre.attributeSources.set(key, inheritedSource);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const [key, value] of Object.entries(inherited.children)) {
|
|
198
|
+
if (!(key in pre.children)) {
|
|
199
|
+
pre.children[key] = value;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
resolutions++;
|
|
203
|
+
}
|
|
204
|
+
visiting.delete(path);
|
|
205
|
+
resolved.add(path);
|
|
206
|
+
return { resolutions, crossLayer };
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Compose a single node and its children.
|
|
210
|
+
*/
|
|
211
|
+
function composeNode(path, preComposed, composed, visiting, layers, pathIndex) {
|
|
212
|
+
// Already composed?
|
|
213
|
+
const existing = composed.get(path);
|
|
214
|
+
if (existing)
|
|
215
|
+
return existing;
|
|
216
|
+
// Cycle detection
|
|
217
|
+
if (visiting.has(path)) {
|
|
218
|
+
// Return a stub to break the cycle
|
|
219
|
+
const stub = {
|
|
220
|
+
path,
|
|
221
|
+
attributes: new Map(),
|
|
222
|
+
children: new Map(),
|
|
223
|
+
attributeSources: new Map(),
|
|
224
|
+
contributingLayers: new Set(),
|
|
225
|
+
};
|
|
226
|
+
composed.set(path, stub);
|
|
227
|
+
return stub;
|
|
228
|
+
}
|
|
229
|
+
visiting.add(path);
|
|
230
|
+
const pre = preComposed.get(path);
|
|
231
|
+
const node = {
|
|
232
|
+
path,
|
|
233
|
+
attributes: new Map(),
|
|
234
|
+
children: new Map(),
|
|
235
|
+
attributeSources: new Map(),
|
|
236
|
+
contributingLayers: new Set(pre?.definedInLayers || []),
|
|
237
|
+
};
|
|
238
|
+
if (pre) {
|
|
239
|
+
// Copy attributes
|
|
240
|
+
for (const [key, value] of Object.entries(pre.attributes)) {
|
|
241
|
+
node.attributes.set(key, value);
|
|
242
|
+
// Track source
|
|
243
|
+
const sourceLayerId = pre.attributeSources.get(key);
|
|
244
|
+
if (sourceLayerId) {
|
|
245
|
+
const layer = layers.find((l) => l.id === sourceLayerId);
|
|
246
|
+
if (layer) {
|
|
247
|
+
node.attributeSources.set(key, {
|
|
248
|
+
layerId: layer.id,
|
|
249
|
+
layerName: layer.name,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Resolve and add children
|
|
255
|
+
for (const [name, childPath] of Object.entries(pre.children)) {
|
|
256
|
+
if (!childPath)
|
|
257
|
+
continue;
|
|
258
|
+
// Child path might be hierarchical (uuid/ChildName) - resolve via pathIndex
|
|
259
|
+
const resolvedChildPath = pathIndex.resolvePath(childPath) || childPath;
|
|
260
|
+
const childPre = preComposed.get(resolvedChildPath);
|
|
261
|
+
if (childPre) {
|
|
262
|
+
const child = composeNode(resolvedChildPath, preComposed, composed, visiting, layers, pathIndex);
|
|
263
|
+
child.parent = node;
|
|
264
|
+
node.children.set(name, child);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
visiting.delete(path);
|
|
269
|
+
composed.set(path, node);
|
|
270
|
+
return node;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Find root nodes (nodes with no parent).
|
|
274
|
+
*/
|
|
275
|
+
function findRoots(composed) {
|
|
276
|
+
const childPaths = new Set();
|
|
277
|
+
// Collect all child paths
|
|
278
|
+
for (const node of composed.values()) {
|
|
279
|
+
for (const child of node.children.values()) {
|
|
280
|
+
childPaths.add(child.path);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Roots are nodes not referenced as children
|
|
284
|
+
const roots = [];
|
|
285
|
+
for (const node of composed.values()) {
|
|
286
|
+
if (!childPaths.has(node.path) && !node.parent) {
|
|
287
|
+
roots.push(node);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return roots;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Compose a single IFCX file (convenience wrapper).
|
|
294
|
+
*/
|
|
295
|
+
export function composeSingleFile(file) {
|
|
296
|
+
const stack = new LayerStack();
|
|
297
|
+
stack.addLayer(file, new ArrayBuffer(0), 'single');
|
|
298
|
+
return composeFederated(stack);
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=federated-composition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federated-composition.js","sourceRoot":"","sources":["../src/federated-composition.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { type MeshData } from './geometry-extractor.js';
|
|
2
2
|
import { StringTable } from '@ifc-lite/data';
|
|
3
3
|
import type { SpatialHierarchy, EntityTable, PropertyTable, QuantityTable, RelationshipGraph } from '@ifc-lite/data';
|
|
4
|
+
import { LayerStack } from './layer-stack.js';
|
|
5
|
+
import { PathIndex } from './path-resolver.js';
|
|
4
6
|
export * from './types.js';
|
|
5
7
|
export { composeIfcx, findRoots, getDescendants, getPathToRoot } from './composition.js';
|
|
6
8
|
export { extractEntities } from './entity-extractor.js';
|
|
7
9
|
export { extractProperties, isQuantityProperty } from './property-extractor.js';
|
|
8
10
|
export { extractGeometry, type MeshData } from './geometry-extractor.js';
|
|
9
11
|
export { buildHierarchy } from './hierarchy-builder.js';
|
|
12
|
+
export { LayerStack, createLayerStack, type IfcxLayer, type LayerSource, } from './layer-stack.js';
|
|
13
|
+
export { PathIndex, createPathIndex, parsePath, type ParsedPath, type PathEntry, } from './path-resolver.js';
|
|
14
|
+
export { composeFederated, type ComposeOptions, type FederatedCompositionResult, type ComposedNodeWithSources, } from './federated-composition.js';
|
|
10
15
|
/**
|
|
11
16
|
* Result of parsing an IFCX file.
|
|
12
17
|
* Compatible with existing ifc-lite data structures.
|
|
@@ -54,4 +59,64 @@ export declare function parseIfcx(buffer: ArrayBuffer, options?: IfcxParseOption
|
|
|
54
59
|
* Detect if a buffer contains IFCX (JSON) or IFC (STEP) format.
|
|
55
60
|
*/
|
|
56
61
|
export declare function detectFormat(buffer: ArrayBuffer): 'ifcx' | 'ifc' | 'unknown';
|
|
62
|
+
/**
|
|
63
|
+
* Input for federated parsing - a buffer with a name.
|
|
64
|
+
*/
|
|
65
|
+
export interface FederatedFileInput {
|
|
66
|
+
buffer: ArrayBuffer;
|
|
67
|
+
name: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Options for federated IFCX parsing.
|
|
71
|
+
*/
|
|
72
|
+
export interface FederatedParseOptions extends IfcxParseOptions {
|
|
73
|
+
/** Maximum inheritance depth (default: 10) */
|
|
74
|
+
maxInheritDepth?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Result of parsing federated IFCX files.
|
|
78
|
+
* Extends the standard result with layer information.
|
|
79
|
+
*/
|
|
80
|
+
export interface FederatedIfcxParseResult extends IfcxParseResult {
|
|
81
|
+
/** Layer stack with all loaded layers */
|
|
82
|
+
layerStack: LayerStack;
|
|
83
|
+
/** Path index for cross-file lookups */
|
|
84
|
+
pathIndex: PathIndex;
|
|
85
|
+
/** Composition statistics */
|
|
86
|
+
compositionStats: {
|
|
87
|
+
layersUsed: number;
|
|
88
|
+
inheritanceResolutions: number;
|
|
89
|
+
crossLayerReferences: number;
|
|
90
|
+
};
|
|
91
|
+
/** Map from path to layer IDs that define it */
|
|
92
|
+
pathToLayers: Map<string, string[]>;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Parse multiple IFCX files as federated layers.
|
|
96
|
+
*
|
|
97
|
+
* Files are loaded as layers with the first file being the base (weakest)
|
|
98
|
+
* and subsequent files being overlays (stronger). Layer order can be
|
|
99
|
+
* adjusted after parsing using the returned LayerStack.
|
|
100
|
+
*
|
|
101
|
+
* @param files - Array of file buffers with names
|
|
102
|
+
* @param options - Parse options
|
|
103
|
+
* @returns Federated parse result with layer information
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* const result = await parseFederatedIfcx([
|
|
108
|
+
* { buffer: baseBuffer, name: 'hello-wall.ifcx' },
|
|
109
|
+
* { buffer: overlayBuffer, name: 'add-fire-rating.ifcx' },
|
|
110
|
+
* ]);
|
|
111
|
+
*
|
|
112
|
+
* // Wall now has FireRating property from overlay
|
|
113
|
+
* const wallProps = result.properties.getForEntity(wallId);
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare function parseFederatedIfcx(files: FederatedFileInput[], options?: FederatedParseOptions): Promise<FederatedIfcxParseResult>;
|
|
117
|
+
/**
|
|
118
|
+
* Add an overlay layer to an existing federated result.
|
|
119
|
+
* Returns a new result with the overlay applied.
|
|
120
|
+
*/
|
|
121
|
+
export declare function addIfcxOverlay(baseResult: FederatedIfcxParseResult, overlayBuffer: ArrayBuffer, overlayName: string, options?: FederatedParseOptions): Promise<FederatedIfcxParseResult>;
|
|
57
122
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEzE,OAAO,EACL,WAAW,EAIZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGrH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,9 @@ import { extractProperties, isQuantityProperty } from './property-extractor.js';
|
|
|
7
7
|
import { extractGeometry } from './geometry-extractor.js';
|
|
8
8
|
import { buildHierarchy } from './hierarchy-builder.js';
|
|
9
9
|
import { StringTable, RelationshipGraphBuilder, RelationshipType, QuantityTableBuilder, } from '@ifc-lite/data';
|
|
10
|
+
// Federated composition imports
|
|
11
|
+
import { createLayerStack } from './layer-stack.js';
|
|
12
|
+
import { composeFederated, } from './federated-composition.js';
|
|
10
13
|
// Re-export types
|
|
11
14
|
export * from './types.js';
|
|
12
15
|
export { composeIfcx, findRoots, getDescendants, getPathToRoot } from './composition.js';
|
|
@@ -14,6 +17,10 @@ export { extractEntities } from './entity-extractor.js';
|
|
|
14
17
|
export { extractProperties, isQuantityProperty } from './property-extractor.js';
|
|
15
18
|
export { extractGeometry } from './geometry-extractor.js';
|
|
16
19
|
export { buildHierarchy } from './hierarchy-builder.js';
|
|
20
|
+
// Re-export federated composition
|
|
21
|
+
export { LayerStack, createLayerStack, } from './layer-stack.js';
|
|
22
|
+
export { PathIndex, createPathIndex, parsePath, } from './path-resolver.js';
|
|
23
|
+
export { composeFederated, } from './federated-composition.js';
|
|
17
24
|
/**
|
|
18
25
|
* Parse an IFCX file and return data compatible with existing ifc-lite pipeline.
|
|
19
26
|
*/
|
|
@@ -186,4 +193,165 @@ export function detectFormat(buffer) {
|
|
|
186
193
|
}
|
|
187
194
|
return 'unknown';
|
|
188
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Parse multiple IFCX files as federated layers.
|
|
198
|
+
*
|
|
199
|
+
* Files are loaded as layers with the first file being the base (weakest)
|
|
200
|
+
* and subsequent files being overlays (stronger). Layer order can be
|
|
201
|
+
* adjusted after parsing using the returned LayerStack.
|
|
202
|
+
*
|
|
203
|
+
* @param files - Array of file buffers with names
|
|
204
|
+
* @param options - Parse options
|
|
205
|
+
* @returns Federated parse result with layer information
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* const result = await parseFederatedIfcx([
|
|
210
|
+
* { buffer: baseBuffer, name: 'hello-wall.ifcx' },
|
|
211
|
+
* { buffer: overlayBuffer, name: 'add-fire-rating.ifcx' },
|
|
212
|
+
* ]);
|
|
213
|
+
*
|
|
214
|
+
* // Wall now has FireRating property from overlay
|
|
215
|
+
* const wallProps = result.properties.getForEntity(wallId);
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
export async function parseFederatedIfcx(files, options = {}) {
|
|
219
|
+
const startTime = performance.now();
|
|
220
|
+
if (files.length === 0) {
|
|
221
|
+
throw new Error('At least one IFCX file is required');
|
|
222
|
+
}
|
|
223
|
+
options.onProgress?.({ phase: 'parse', percent: 0 });
|
|
224
|
+
// Phase 1: Parse all files and build layer stack
|
|
225
|
+
const layerStack = createLayerStack();
|
|
226
|
+
let totalSize = 0;
|
|
227
|
+
for (let i = 0; i < files.length; i++) {
|
|
228
|
+
const { buffer, name } = files[i];
|
|
229
|
+
totalSize += buffer.byteLength;
|
|
230
|
+
const text = new TextDecoder().decode(buffer);
|
|
231
|
+
let file;
|
|
232
|
+
try {
|
|
233
|
+
file = JSON.parse(text);
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
throw new Error(`Invalid IFCX file "${name}": JSON parse error - ${e}`);
|
|
237
|
+
}
|
|
238
|
+
// Validate header
|
|
239
|
+
if (!file.header?.ifcxVersion?.toLowerCase().includes('ifcx')) {
|
|
240
|
+
throw new Error(`Invalid IFCX file "${name}": missing or invalid header.ifcxVersion`);
|
|
241
|
+
}
|
|
242
|
+
// Add as layer (first file is weakest, last is strongest)
|
|
243
|
+
// We add at position 0 so later files become strongest
|
|
244
|
+
layerStack.addLayerAt(file, buffer, name, 0, {
|
|
245
|
+
type: 'file',
|
|
246
|
+
filename: name,
|
|
247
|
+
size: buffer.byteLength,
|
|
248
|
+
});
|
|
249
|
+
options.onProgress?.({
|
|
250
|
+
phase: 'parse',
|
|
251
|
+
percent: Math.round(((i + 1) / files.length) * 100),
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
options.onProgress?.({ phase: 'compose', percent: 0 });
|
|
255
|
+
// Phase 2: Compose federated layers
|
|
256
|
+
const compositionResult = composeFederated(layerStack, {
|
|
257
|
+
onProgress: (phase, percent) => {
|
|
258
|
+
options.onProgress?.({ phase: `compose-${phase}`, percent });
|
|
259
|
+
},
|
|
260
|
+
maxInheritDepth: options.maxInheritDepth,
|
|
261
|
+
});
|
|
262
|
+
options.onProgress?.({ phase: 'compose', percent: 100 });
|
|
263
|
+
// Convert composed nodes to standard ComposedNode format for extractors
|
|
264
|
+
const composed = new Map();
|
|
265
|
+
for (const [path, node] of compositionResult.composed) {
|
|
266
|
+
composed.set(path, node);
|
|
267
|
+
}
|
|
268
|
+
// Phase 3: Extract entities
|
|
269
|
+
options.onProgress?.({ phase: 'entities', percent: 0 });
|
|
270
|
+
const strings = new StringTable();
|
|
271
|
+
const { entities, pathToId, idToPath } = extractEntities(composed, strings);
|
|
272
|
+
options.onProgress?.({ phase: 'entities', percent: 100 });
|
|
273
|
+
// Phase 4: Extract properties
|
|
274
|
+
options.onProgress?.({ phase: 'properties', percent: 0 });
|
|
275
|
+
const properties = extractProperties(composed, pathToId, strings);
|
|
276
|
+
options.onProgress?.({ phase: 'properties', percent: 100 });
|
|
277
|
+
// Phase 5: Extract geometry
|
|
278
|
+
options.onProgress?.({ phase: 'geometry', percent: 0 });
|
|
279
|
+
const meshes = extractGeometry(composed, pathToId);
|
|
280
|
+
options.onProgress?.({ phase: 'geometry', percent: 100 });
|
|
281
|
+
// Phase 6: Build hierarchy
|
|
282
|
+
options.onProgress?.({ phase: 'hierarchy', percent: 0 });
|
|
283
|
+
const spatialHierarchy = buildHierarchy(composed, pathToId);
|
|
284
|
+
options.onProgress?.({ phase: 'hierarchy', percent: 100 });
|
|
285
|
+
// Phase 7: Build relationships
|
|
286
|
+
options.onProgress?.({ phase: 'relationships', percent: 0 });
|
|
287
|
+
const relationships = buildRelationships(composed, pathToId);
|
|
288
|
+
options.onProgress?.({ phase: 'relationships', percent: 100 });
|
|
289
|
+
// Phase 8: Build quantities
|
|
290
|
+
const quantities = buildQuantities(composed, pathToId, strings);
|
|
291
|
+
// Build path-to-layers map
|
|
292
|
+
const pathToLayers = new Map();
|
|
293
|
+
for (const [path, node] of compositionResult.composed) {
|
|
294
|
+
pathToLayers.set(path, Array.from(node.contributingLayers));
|
|
295
|
+
}
|
|
296
|
+
const parseTime = performance.now() - startTime;
|
|
297
|
+
return {
|
|
298
|
+
entities,
|
|
299
|
+
properties,
|
|
300
|
+
quantities,
|
|
301
|
+
relationships,
|
|
302
|
+
spatialHierarchy,
|
|
303
|
+
strings,
|
|
304
|
+
meshes,
|
|
305
|
+
pathToId,
|
|
306
|
+
idToPath,
|
|
307
|
+
schemaVersion: 'IFC5',
|
|
308
|
+
fileSize: totalSize,
|
|
309
|
+
entityCount: entities.count,
|
|
310
|
+
parseTime,
|
|
311
|
+
// Federated-specific fields
|
|
312
|
+
layerStack,
|
|
313
|
+
pathIndex: compositionResult.pathIndex,
|
|
314
|
+
compositionStats: {
|
|
315
|
+
layersUsed: compositionResult.stats.layersUsed,
|
|
316
|
+
inheritanceResolutions: compositionResult.stats.inheritanceResolutions,
|
|
317
|
+
crossLayerReferences: compositionResult.stats.crossLayerReferences,
|
|
318
|
+
},
|
|
319
|
+
pathToLayers,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Add an overlay layer to an existing federated result.
|
|
324
|
+
* Returns a new result with the overlay applied.
|
|
325
|
+
*/
|
|
326
|
+
export async function addIfcxOverlay(baseResult, overlayBuffer, overlayName, options = {}) {
|
|
327
|
+
// Parse overlay file
|
|
328
|
+
const text = new TextDecoder().decode(overlayBuffer);
|
|
329
|
+
let file;
|
|
330
|
+
try {
|
|
331
|
+
file = JSON.parse(text);
|
|
332
|
+
}
|
|
333
|
+
catch (e) {
|
|
334
|
+
throw new Error(`Invalid IFCX overlay "${overlayName}": JSON parse error - ${e}`);
|
|
335
|
+
}
|
|
336
|
+
// Validate header
|
|
337
|
+
if (!file.header?.ifcxVersion?.toLowerCase().includes('ifcx')) {
|
|
338
|
+
throw new Error(`Invalid IFCX overlay "${overlayName}": missing or invalid header.ifcxVersion`);
|
|
339
|
+
}
|
|
340
|
+
// Add to layer stack (at top = strongest)
|
|
341
|
+
baseResult.layerStack.addLayer(file, overlayBuffer, overlayName, {
|
|
342
|
+
type: 'file',
|
|
343
|
+
filename: overlayName,
|
|
344
|
+
size: overlayBuffer.byteLength,
|
|
345
|
+
});
|
|
346
|
+
// Re-compose with new layer
|
|
347
|
+
// Collect all files from the layer stack
|
|
348
|
+
const files = baseResult.layerStack
|
|
349
|
+
.getLayers()
|
|
350
|
+
.map((layer) => ({
|
|
351
|
+
buffer: layer.buffer,
|
|
352
|
+
name: layer.name,
|
|
353
|
+
}))
|
|
354
|
+
.reverse(); // Reverse because layers are stored strongest-first
|
|
355
|
+
return parseFederatedIfcx(files, options);
|
|
356
|
+
}
|
|
189
357
|
//# sourceMappingURL=index.js.map
|