@ifc-lite/cli 0.11.1 → 0.11.2
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/commands/ids.d.ts.map +1 -1
- package/dist/commands/ids.js +19 -176
- package/dist/commands/ids.js.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/commands/ids.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/commands/ids.ts"],"names":[],"mappings":"AAyBA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4D9D"}
|
package/dist/commands/ids.js
CHANGED
|
@@ -9,9 +9,7 @@
|
|
|
9
9
|
import { readFile } from 'node:fs/promises';
|
|
10
10
|
import { createHeadlessContext } from '../loader.js';
|
|
11
11
|
import { printJson, hasFlag, getFlag, fatal } from '../output.js';
|
|
12
|
-
import {
|
|
13
|
-
import { extractClassificationsOnDemand, extractMaterialsOnDemand, extractAllEntityAttributes, extractTypeEntityOwnProperties, } from '@ifc-lite/parser';
|
|
14
|
-
import { RelationshipType } from '@ifc-lite/data';
|
|
12
|
+
import { createDataAccessor } from '@ifc-lite/ids/bridge';
|
|
15
13
|
export async function idsCommand(args) {
|
|
16
14
|
const positional = args.filter(a => !a.startsWith('-'));
|
|
17
15
|
if (positional.length < 2)
|
|
@@ -24,196 +22,41 @@ export async function idsCommand(args) {
|
|
|
24
22
|
const idsContent = await readFile(idsPath, 'utf-8');
|
|
25
23
|
// Parse and validate
|
|
26
24
|
const idsDoc = await bim.ids.parse(idsContent);
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
const
|
|
25
|
+
// The shared bridge accessor is the canonical IfcDataStore →
|
|
26
|
+
// IFCDataAccessor projection (same one the viewer and MCP server use).
|
|
27
|
+
const accessor = createDataAccessor(store);
|
|
28
|
+
const report = (await bim.ids.validate(idsDoc, {
|
|
30
29
|
accessor,
|
|
31
30
|
modelInfo: { schemaVersion: store.schemaVersion },
|
|
32
31
|
locale,
|
|
32
|
+
// For human-readable output only the failures matter; dropping
|
|
33
|
+
// passing entity results keeps the report bounded on large models.
|
|
34
|
+
includePassingEntities: jsonOutput,
|
|
33
35
|
onProgress: (p) => {
|
|
34
|
-
if (!jsonOutput) {
|
|
35
|
-
|
|
36
|
+
if (!jsonOutput && p.phase !== 'complete') {
|
|
37
|
+
const spec = Math.min(p.specificationIndex + 1, p.totalSpecifications);
|
|
38
|
+
process.stderr.write(`\r Validating: spec ${spec}/${p.totalSpecifications} (${p.percentage}%)`);
|
|
36
39
|
}
|
|
37
40
|
},
|
|
38
|
-
});
|
|
41
|
+
}));
|
|
39
42
|
if (!jsonOutput)
|
|
40
43
|
process.stderr.write('\n');
|
|
41
|
-
const summary = bim.ids.summarize(report);
|
|
42
44
|
if (jsonOutput) {
|
|
45
|
+
// Keep the established machine-readable summary shape.
|
|
46
|
+
const summary = bim.ids.summarize(report);
|
|
43
47
|
printJson({ summary, report });
|
|
44
48
|
return;
|
|
45
49
|
}
|
|
50
|
+
// The validator computes its summary from full per-spec counts, so it
|
|
51
|
+
// stays correct even though passing entity results are not retained.
|
|
52
|
+
const summary = report.summary;
|
|
46
53
|
process.stdout.write(`\n IDS Validation Results\n`);
|
|
47
54
|
process.stdout.write(` ─────────────────────\n`);
|
|
48
55
|
process.stdout.write(` Specifications: ${summary.passedSpecifications}/${summary.totalSpecifications} passed\n`);
|
|
49
|
-
process.stdout.write(` Entities: ${summary.
|
|
50
|
-
process.stdout.write(` Failed: ${summary.
|
|
56
|
+
process.stdout.write(` Entities: ${summary.totalEntitiesPassed}/${summary.totalEntitiesChecked} passed\n`);
|
|
57
|
+
process.stdout.write(` Failed: ${summary.totalEntitiesFailed} entities in ${summary.failedSpecifications} specs\n`);
|
|
51
58
|
const exitCode = summary.failedSpecifications > 0 ? 1 : 0;
|
|
52
59
|
process.stdout.write(`\n Result: ${exitCode === 0 ? 'PASS' : 'FAIL'}\n\n`);
|
|
53
60
|
process.exitCode = exitCode;
|
|
54
61
|
}
|
|
55
|
-
const REL_TYPE_MAP = {
|
|
56
|
-
IfcRelAggregates: RelationshipType.Aggregates,
|
|
57
|
-
IfcRelContainedInSpatialStructure: RelationshipType.ContainsElements,
|
|
58
|
-
IfcRelNests: RelationshipType.Aggregates, // closest mapping
|
|
59
|
-
IfcRelVoidsElement: RelationshipType.VoidsElement,
|
|
60
|
-
IfcRelFillsElement: RelationshipType.FillsElement,
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* Build a complete IFCDataAccessor for the IDS validator.
|
|
64
|
-
* Implements all 12+ methods the validator expects.
|
|
65
|
-
*/
|
|
66
|
-
function buildIdsAccessor(store) {
|
|
67
|
-
return {
|
|
68
|
-
getEntityType(expressId) {
|
|
69
|
-
return store.entities.getTypeName(expressId) || undefined;
|
|
70
|
-
},
|
|
71
|
-
getEntityName(expressId) {
|
|
72
|
-
const node = new EntityNode(store, expressId);
|
|
73
|
-
return node.name || undefined;
|
|
74
|
-
},
|
|
75
|
-
getGlobalId(expressId) {
|
|
76
|
-
const node = new EntityNode(store, expressId);
|
|
77
|
-
return node.globalId || undefined;
|
|
78
|
-
},
|
|
79
|
-
getDescription(expressId) {
|
|
80
|
-
const node = new EntityNode(store, expressId);
|
|
81
|
-
return node.description || undefined;
|
|
82
|
-
},
|
|
83
|
-
getObjectType(expressId) {
|
|
84
|
-
// Try EntityNode's objectType first (works for IfcObject subtypes)
|
|
85
|
-
const node = new EntityNode(store, expressId);
|
|
86
|
-
if (node.objectType)
|
|
87
|
-
return node.objectType;
|
|
88
|
-
// For IfcTypeObject subtypes (IfcWallType, etc.), extract PredefinedType
|
|
89
|
-
// from entity attributes since they don't have ObjectType.
|
|
90
|
-
const allAttrs = extractAllEntityAttributes(store, expressId);
|
|
91
|
-
const predefinedType = allAttrs.find(a => a.name === 'PredefinedType');
|
|
92
|
-
if (predefinedType?.value && predefinedType.value !== 'NOTDEFINED') {
|
|
93
|
-
return typeof predefinedType.value === 'string' ? predefinedType.value : String(predefinedType.value);
|
|
94
|
-
}
|
|
95
|
-
// If PredefinedType is USERDEFINED/absent, check ObjectType from full attributes
|
|
96
|
-
const objTypeAttr = allAttrs.find(a => a.name === 'ObjectType');
|
|
97
|
-
if (objTypeAttr?.value) {
|
|
98
|
-
return typeof objTypeAttr.value === 'string' ? objTypeAttr.value : String(objTypeAttr.value);
|
|
99
|
-
}
|
|
100
|
-
return undefined;
|
|
101
|
-
},
|
|
102
|
-
getEntitiesByType(typeName) {
|
|
103
|
-
const upper = typeName.toUpperCase();
|
|
104
|
-
return [...(store.entityIndex.byType.get(upper) ?? [])];
|
|
105
|
-
},
|
|
106
|
-
getAllEntityIds() {
|
|
107
|
-
const ids = [];
|
|
108
|
-
for (const [, typeIds] of store.entityIndex.byType) {
|
|
109
|
-
for (const id of typeIds)
|
|
110
|
-
ids.push(id);
|
|
111
|
-
}
|
|
112
|
-
return ids;
|
|
113
|
-
},
|
|
114
|
-
getPropertyValue(expressId, propertySetName, propertyName) {
|
|
115
|
-
const node = new EntityNode(store, expressId);
|
|
116
|
-
const psets = node.properties();
|
|
117
|
-
for (const pset of psets) {
|
|
118
|
-
if (pset.name === propertySetName) {
|
|
119
|
-
for (const prop of pset.properties) {
|
|
120
|
-
if (prop.name === propertyName) {
|
|
121
|
-
return {
|
|
122
|
-
value: prop.value ?? null,
|
|
123
|
-
dataType: prop.type ?? 'IFCLABEL',
|
|
124
|
-
propertySetName: pset.name,
|
|
125
|
-
propertyName: prop.name,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return undefined;
|
|
132
|
-
},
|
|
133
|
-
getPropertySets(expressId) {
|
|
134
|
-
// Try EntityNode first (relationship-based properties for IfcObject instances)
|
|
135
|
-
const node = new EntityNode(store, expressId);
|
|
136
|
-
const psets = node.properties();
|
|
137
|
-
const mapPsets = (rawPsets) => rawPsets.map(pset => ({
|
|
138
|
-
name: pset.name,
|
|
139
|
-
properties: pset.properties.map(p => ({
|
|
140
|
-
name: p.name,
|
|
141
|
-
value: p.value ?? null,
|
|
142
|
-
dataType: p.type ?? 'IFCLABEL',
|
|
143
|
-
})),
|
|
144
|
-
}));
|
|
145
|
-
if (psets.length > 0) {
|
|
146
|
-
return mapPsets(psets);
|
|
147
|
-
}
|
|
148
|
-
// For IfcTypeObject subtypes, extract from HasPropertySets attribute
|
|
149
|
-
const typePsets = extractTypeEntityOwnProperties(store, expressId);
|
|
150
|
-
if (typePsets.length > 0) {
|
|
151
|
-
return mapPsets(typePsets);
|
|
152
|
-
}
|
|
153
|
-
return [];
|
|
154
|
-
},
|
|
155
|
-
getClassifications(expressId) {
|
|
156
|
-
const classifications = extractClassificationsOnDemand(store, expressId);
|
|
157
|
-
return classifications.map(c => ({
|
|
158
|
-
system: c.system ?? '',
|
|
159
|
-
value: c.identification ?? '',
|
|
160
|
-
name: c.name ?? undefined,
|
|
161
|
-
}));
|
|
162
|
-
},
|
|
163
|
-
getMaterials(expressId) {
|
|
164
|
-
const materialData = extractMaterialsOnDemand(store, expressId);
|
|
165
|
-
if (!materialData)
|
|
166
|
-
return [];
|
|
167
|
-
const materials = [];
|
|
168
|
-
if (materialData.name) {
|
|
169
|
-
materials.push({ name: materialData.name });
|
|
170
|
-
}
|
|
171
|
-
if (materialData.layers) {
|
|
172
|
-
for (const layer of materialData.layers) {
|
|
173
|
-
if (layer.materialName) {
|
|
174
|
-
materials.push({ name: layer.materialName, category: layer.category ?? undefined });
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return materials;
|
|
179
|
-
},
|
|
180
|
-
getParent(expressId, relationType) {
|
|
181
|
-
const relEnum = REL_TYPE_MAP[relationType];
|
|
182
|
-
if (relEnum === undefined)
|
|
183
|
-
return undefined;
|
|
184
|
-
const parents = store.relationships.getRelated(expressId, relEnum, 'inverse');
|
|
185
|
-
if (parents.length === 0)
|
|
186
|
-
return undefined;
|
|
187
|
-
const parentId = parents[0];
|
|
188
|
-
const parentType = store.entities.getTypeName(parentId);
|
|
189
|
-
// Extract predefinedType from parent entity attributes
|
|
190
|
-
const parentAttrs = extractAllEntityAttributes(store, parentId);
|
|
191
|
-
const parentPredefined = parentAttrs.find(a => a.name === 'PredefinedType');
|
|
192
|
-
const predefinedType = parentPredefined?.value && parentPredefined.value !== 'NOTDEFINED'
|
|
193
|
-
? parentPredefined.value
|
|
194
|
-
: undefined;
|
|
195
|
-
return {
|
|
196
|
-
expressId: parentId,
|
|
197
|
-
entityType: parentType ?? '',
|
|
198
|
-
predefinedType,
|
|
199
|
-
};
|
|
200
|
-
},
|
|
201
|
-
getAttribute(expressId, attributeName) {
|
|
202
|
-
const node = new EntityNode(store, expressId);
|
|
203
|
-
switch (attributeName) {
|
|
204
|
-
case 'Name': return node.name || undefined;
|
|
205
|
-
case 'Description': return node.description || undefined;
|
|
206
|
-
case 'ObjectType': return node.objectType || undefined;
|
|
207
|
-
case 'GlobalId': return node.globalId || undefined;
|
|
208
|
-
case 'Tag': return node.tag || undefined;
|
|
209
|
-
default: {
|
|
210
|
-
// Fall back to full attribute extraction
|
|
211
|
-
const attrs = extractAllEntityAttributes(store, expressId);
|
|
212
|
-
const attr = attrs.find(a => a.name === attributeName);
|
|
213
|
-
return attr?.value != null ? String(attr.value) : undefined;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
62
|
//# sourceMappingURL=ids.js.map
|
package/dist/commands/ids.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/commands/ids.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/commands/ids.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ifc-lite/cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "CLI toolkit for IFC files — query, validate, export, create, and script BIM data",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
"@ifc-lite/encoding": "^1.14.7",
|
|
28
28
|
"@ifc-lite/export": "^1.19.5",
|
|
29
29
|
"@ifc-lite/extensions": "^0.3.2",
|
|
30
|
-
"@ifc-lite/geometry": "^2.
|
|
31
|
-
"@ifc-lite/ids": "^1.15.
|
|
30
|
+
"@ifc-lite/geometry": "^2.5.1",
|
|
31
|
+
"@ifc-lite/ids": "^1.15.9",
|
|
32
32
|
"@ifc-lite/mcp": "^0.3.2",
|
|
33
33
|
"@ifc-lite/mutations": "^1.15.3",
|
|
34
|
-
"@ifc-lite/parser": "^3.1.
|
|
34
|
+
"@ifc-lite/parser": "^3.1.3",
|
|
35
35
|
"@ifc-lite/query": "^1.14.10",
|
|
36
36
|
"@ifc-lite/sandbox": "^1.15.2",
|
|
37
|
-
"@ifc-lite/sdk": "^1.18.
|
|
37
|
+
"@ifc-lite/sdk": "^1.18.2",
|
|
38
38
|
"@ifc-lite/viewer-core": "^0.2.6",
|
|
39
|
-
"@ifc-lite/wasm": "^2.
|
|
39
|
+
"@ifc-lite/wasm": "^2.6.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^25.9.2",
|