@bldrs-ai/conway 1.346.1102 → 1.348.1109

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 (26) hide show
  1. package/compiled/examples/browser-bundled.cjs +1 -1
  2. package/compiled/examples/cli-bundled.cjs +1 -1
  3. package/compiled/examples/cli-step-bundled.cjs +1 -1
  4. package/compiled/examples/validator-bundled.cjs +1 -1
  5. package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.d.ts +144 -0
  6. package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.d.ts.map +1 -0
  7. package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.js +236 -0
  8. package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.test.d.ts +2 -0
  9. package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.test.d.ts.map +1 -0
  10. package/compiled/src/AP214E3_2010/ap214_product_structure_extraction.test.js +107 -0
  11. package/compiled/src/AP214E3_2010/ap214_property_extraction.d.ts +90 -0
  12. package/compiled/src/AP214E3_2010/ap214_property_extraction.d.ts.map +1 -0
  13. package/compiled/src/AP214E3_2010/ap214_property_extraction.js +143 -0
  14. package/compiled/src/AP214E3_2010/ap214_property_extraction.test.d.ts +2 -0
  15. package/compiled/src/AP214E3_2010/ap214_property_extraction.test.d.ts.map +1 -0
  16. package/compiled/src/AP214E3_2010/ap214_property_extraction.test.js +56 -0
  17. package/compiled/src/compat/web-ifc/ap214_properties.d.ts +140 -13
  18. package/compiled/src/compat/web-ifc/ap214_properties.d.ts.map +1 -1
  19. package/compiled/src/compat/web-ifc/ap214_properties.js +267 -26
  20. package/compiled/src/compat/web-ifc/ap214_properties.test.d.ts +2 -0
  21. package/compiled/src/compat/web-ifc/ap214_properties.test.d.ts.map +1 -0
  22. package/compiled/src/compat/web-ifc/ap214_properties.test.js +85 -0
  23. package/compiled/src/version/version.d.ts.map +1 -1
  24. package/compiled/src/version/version.js +8 -1
  25. package/compiled/tsconfig.tsbuildinfo +1 -1
  26. package/package.json +1 -1
@@ -1,51 +1,292 @@
1
- /* eslint-disable */
2
- import { shape_definition_representation } from "../../AP214E3_2010/AP214E3_2010_gen/shape_definition_representation.gen.js";
3
- import { product } from "../../AP214E3_2010/AP214E3_2010_gen/product.gen.js";
1
+ import { AP214ProductStructureExtraction, } from "../../AP214E3_2010/ap214_product_structure_extraction.js";
2
+ import { AP214PropertyExtraction, } from "../../AP214E3_2010/ap214_property_extraction.js";
3
+ /**
4
+ * web-ifc tape type code for an entity reference. `unpackHelper` rejects any
5
+ * `HasProperties` entry whose `type` is not this.
6
+ */
7
+ const WEB_IFC_REF_TYPE = 5;
8
+ /** Express id used for a synthetic root when a file has multiple roots. */
9
+ const SYNTHETIC_ROOT_EXPRESS_ID = 0;
10
+ /**
11
+ * web-ifc-compatible property/spatial surface over an AP214/AP242 step model.
12
+ *
13
+ * Backed by {@link AP214ProductStructureExtraction} and
14
+ * {@link AP214PropertyExtraction}: `getSpatialStructure` returns the real
15
+ * nested, named, occurrence-keyed tree (replacing the old flat, nameless stub);
16
+ * `getItemProperties` / `getPropertySets` return the extracted attribute and
17
+ * validation rows; `getAllItemsOfType` is backed by the model type index.
18
+ *
19
+ * This is the seam Share consumes (via `IfcApiProxyAP214`); nothing in Share
20
+ * changes — it lights up the moment this returns a real tree.
21
+ */
4
22
  export class AP214Properties {
23
+ /**
24
+ * @param api The AP214 passthrough proxy owning the step model.
25
+ */
5
26
  constructor(api) {
6
27
  this.api = api;
7
28
  }
29
+ /**
30
+ * No-op type-name lookup retained for interface compatibility; AP214 surfaces
31
+ * STEP entity names directly on the nodes.
32
+ *
33
+ * @param type The numeric type code.
34
+ * @return {string} The empty string (AP214 has no IFC type-name map).
35
+ */
8
36
  getIfcType(type) {
9
37
  return "";
10
38
  }
39
+ /**
40
+ * Resolve one express id to a web-ifc-shaped item, dispatching on what the id
41
+ * denotes:
42
+ *
43
+ * - a **property single** (a `descriptive_/measure_representation_item` id,
44
+ * referenced from a pset's `HasProperties`) → `{ expressID, Name: {value},
45
+ * NominalValue: {value} }`, the shape `unpackHelper` reads after it
46
+ * dereferences a `HasProperties` handle;
47
+ * - a **tree node** (NAUO occurrence id, or `product_definition[_shape]` id
48
+ * for single-part files) → `{ expressID, Name: {value} }`, the part's
49
+ * identity row.
50
+ *
51
+ * Property-single ids and node ids are disjoint (distinct STEP entities), so
52
+ * the lookup is unambiguous.
53
+ *
54
+ * @param id Express id to resolve.
55
+ * @param recursive Unused; kept for web-ifc signature parity.
56
+ * @return {Promise<object>} The web-ifc-shaped item.
57
+ */
11
58
  async getItemProperties(id, recursive = false) {
12
- return this.api.getLine(id, recursive);
59
+ this.buildIndexes();
60
+ const property = this.propertyByItemId_.get(id);
61
+ if (property !== void 0) {
62
+ return {
63
+ expressID: id,
64
+ Name: { value: property.name },
65
+ NominalValue: { value: property.numericValue ?? property.value },
66
+ };
67
+ }
68
+ return {
69
+ expressID: id,
70
+ Name: { value: this.nodeNameByExpressID_.get(id) ?? "" },
71
+ };
13
72
  }
73
+ /**
74
+ * Get a part's property sets: one `IfcPropertySet`-shaped set per grouping
75
+ * label (plain attributes vs. validation properties). Each set's
76
+ * `HasProperties` is an array of web-ifc reference handles
77
+ * (`{ type: 5, value: itemExpressID }`) that Share's Properties panel resolves
78
+ * back to individual properties via `getItemProperties` — emitting inline
79
+ * property objects instead would trip `unpackHelper`'s reference-type guard.
80
+ *
81
+ * @param elementID Node express id.
82
+ * @param recursive Unused; kept for web-ifc signature parity.
83
+ * @return {Promise<any[]>} The property sets for the element.
84
+ */
14
85
  async getPropertySets(elementID, recursive = false) {
15
- return [];
86
+ const rows = this.rowsForElement(elementID);
87
+ if (rows.length === 0) {
88
+ return [];
89
+ }
90
+ const byGroup = new Map();
91
+ for (const row of rows) {
92
+ let groupRows = byGroup.get(row.group);
93
+ if (groupRows === void 0) {
94
+ groupRows = [];
95
+ byGroup.set(row.group, groupRows);
96
+ }
97
+ groupRows.push(row);
98
+ }
99
+ const propertySets = [];
100
+ for (const [group, groupRows] of byGroup) {
101
+ const hasProperties = [];
102
+ for (const row of groupRows) {
103
+ if (row.expressID !== void 0) {
104
+ hasProperties.push({ type: WEB_IFC_REF_TYPE, value: row.expressID });
105
+ }
106
+ }
107
+ if (hasProperties.length === 0) {
108
+ continue;
109
+ }
110
+ propertySets.push({
111
+ // The set's own id is never dereferenced by the panel; use the first
112
+ // member's id so it is stable and distinct per group.
113
+ expressID: hasProperties[0].value,
114
+ Name: { value: group.length > 0 ? group : "Attributes" },
115
+ HasProperties: hasProperties,
116
+ });
117
+ }
118
+ return propertySets;
16
119
  }
120
+ /**
121
+ * Type properties are not modeled for AP214 at the Simplified tier.
122
+ *
123
+ * @param elementID Node express id.
124
+ * @param recursive Unused; kept for web-ifc signature parity.
125
+ * @return {Promise<any[]>} An empty array.
126
+ */
17
127
  async getTypeProperties(elementID, recursive = false) {
18
128
  return [];
19
129
  }
130
+ /**
131
+ * Material properties are not modeled for AP214 at the Simplified tier.
132
+ *
133
+ * @param elementID Node express id.
134
+ * @param recursive Unused; kept for web-ifc signature parity.
135
+ * @return {Promise<any[]>} An empty array.
136
+ */
20
137
  async getMaterialsProperties(elementID, recursive = false) {
21
138
  return [];
22
139
  }
140
+ /**
141
+ * Get the real nested, named, occurrence-keyed product structure.
142
+ *
143
+ * @param includeProperties When true, merge each node's item properties onto
144
+ * the node (mirrors the IFC surface's `includeProperties`).
145
+ * @return {Promise<Node>} The root node. A single-root file returns its root
146
+ * directly; a multi-root file is wrapped in a synthetic container root.
147
+ */
23
148
  async getSpatialStructure(includeProperties) {
24
- const model = this.api.StepModel;
25
- const products = Array.from(model.types(product));
26
- const productObj = products[0];
27
- const productNode = AP214Properties.newAP214Product(productObj.expressID);
28
- const shapeDefinitions = model.types(shape_definition_representation);
29
- for (const shapeDefinition of shapeDefinitions) {
30
- const nodeExpressID = shapeDefinition.expressID;
31
- if (nodeExpressID !== void 0) {
32
- productNode.children.push({
33
- expressID: nodeExpressID,
34
- type: "shape_definition",
35
- children: [],
36
- });
37
- }
149
+ const roots = this.productStructure();
150
+ const nodes = await Promise.all(roots.map((root) => this.toSpatialNode(root, includeProperties)));
151
+ if (nodes.length === 1) {
152
+ return nodes[0];
38
153
  }
39
- return productNode;
154
+ const syntheticRoot = {
155
+ expressID: SYNTHETIC_ROOT_EXPRESS_ID,
156
+ type: "product_structure",
157
+ Name: { value: "Model" },
158
+ productDefinitionExpressID: SYNTHETIC_ROOT_EXPRESS_ID,
159
+ occurrencePath: [],
160
+ children: nodes,
161
+ };
162
+ return syntheticRoot;
40
163
  }
164
+ /**
165
+ * Get every element of a STEP entity type, backed by the model type index.
166
+ *
167
+ * @param type The numeric AP214 entity type id.
168
+ * @param verbose When true, return raw line data; otherwise express ids.
169
+ * @return {Promise<any[]>} The matching elements (ids or raw lines).
170
+ */
41
171
  async getAllItemsOfType(type, verbose) {
42
- return [];
172
+ const model = this.api.StepModel;
173
+ const results = [];
174
+ for (const element of model.typeIDs(type)) {
175
+ const expressID = element.expressID;
176
+ if (expressID === void 0) {
177
+ continue;
178
+ }
179
+ results.push(verbose ? this.api.getRawLineData(expressID) : expressID);
180
+ }
181
+ return results;
43
182
  }
44
- static newAP214Product(id) {
45
- return {
46
- expressID: id,
47
- type: "product",
48
- children: [],
183
+ /**
184
+ * Convert an extracted structure node into a spatial node for the compat
185
+ * surface, recursing into children.
186
+ *
187
+ * @param node The extracted product-structure node.
188
+ * @param includeProperties When true, merge the node's item properties.
189
+ * @return {Promise<AP214Node>} The converted spatial node.
190
+ */
191
+ async toSpatialNode(node, includeProperties) {
192
+ const children = await Promise.all(node.children.map((childNode) => this.toSpatialNode(childNode, includeProperties)));
193
+ let spatialNode = {
194
+ expressID: node.expressID,
195
+ type: node.type,
196
+ Name: { value: node.name },
197
+ productDefinitionExpressID: node.productDefinitionExpressID,
198
+ occurrencePath: node.occurrencePath,
199
+ children,
49
200
  };
201
+ if (includeProperties) {
202
+ const properties = await this.getItemProperties(node.expressID);
203
+ spatialNode = { ...properties, ...spatialNode };
204
+ }
205
+ return spatialNode;
206
+ }
207
+ /**
208
+ * Resolve the property rows for an element, mapping an occurrence node id back
209
+ * to its owning product definition (where properties are keyed).
210
+ *
211
+ * @param id Node express id.
212
+ * @return {AP214PropertyRow[]} The element's property rows (possibly empty).
213
+ */
214
+ rowsForElement(id) {
215
+ this.buildIndexes();
216
+ const ownerId = this.ownerByExpressID_.get(id) ?? id;
217
+ const extracted = this.properties().get(ownerId);
218
+ if (extracted === void 0) {
219
+ return [];
220
+ }
221
+ return extracted.map((property) => ({
222
+ expressID: property.expressID,
223
+ Name: property.name,
224
+ value: property.numericValue ?? property.value,
225
+ group: property.group,
226
+ }));
227
+ }
228
+ /**
229
+ * Lazily build and cache every index the surface reads in one pass:
230
+ * - `structureRoots_` — the assembly forest;
231
+ * - `ownerByExpressID_` — node id → owning product-definition id (where the
232
+ * property map is keyed);
233
+ * - `nodeNameByExpressID_` — node id → display name (for `getItemProperties`
234
+ * identity rows);
235
+ * - `propertyByItemId_` — representation-item id → property (so a pset's
236
+ * `HasProperties` reference resolves back to its key/value).
237
+ */
238
+ buildIndexes() {
239
+ if (this.structureRoots_ !== void 0) {
240
+ return;
241
+ }
242
+ const model = this.api.StepModel;
243
+ this.structureRoots_ =
244
+ new AP214ProductStructureExtraction(model).extractProductStructure();
245
+ this.ownerByExpressID_ = new Map();
246
+ this.nodeNameByExpressID_ = new Map();
247
+ for (const root of this.structureRoots_) {
248
+ this.indexNodes(root);
249
+ }
250
+ this.propertyByItemId_ = new Map();
251
+ for (const rows of this.properties().values()) {
252
+ for (const property of rows) {
253
+ if (property.expressID !== void 0) {
254
+ this.propertyByItemId_.set(property.expressID, property);
255
+ }
256
+ }
257
+ }
258
+ }
259
+ /**
260
+ * Record a node's owning product-definition id and display name, recursing
261
+ * into children.
262
+ *
263
+ * @param node The node to index.
264
+ */
265
+ indexNodes(node) {
266
+ this.ownerByExpressID_.set(node.expressID, node.productDefinitionExpressID);
267
+ this.nodeNameByExpressID_.set(node.expressID, node.name);
268
+ for (const childNode of node.children) {
269
+ this.indexNodes(childNode);
270
+ }
271
+ }
272
+ /**
273
+ * Return the cached product-structure forest, building the indexes if needed.
274
+ *
275
+ * @return {ProductStructureNode[]} The cached assembly roots.
276
+ */
277
+ productStructure() {
278
+ this.buildIndexes();
279
+ return this.structureRoots_;
280
+ }
281
+ /**
282
+ * Lazily build and cache the extracted property map.
283
+ *
284
+ * @return {ExtractedPropertyMap} The cached per-part property map.
285
+ */
286
+ properties() {
287
+ if (this.propertyMap_ === void 0) {
288
+ this.propertyMap_ = new AP214PropertyExtraction(this.api.StepModel).extractProperties();
289
+ }
290
+ return this.propertyMap_;
50
291
  }
51
292
  }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ap214_properties.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ap214_properties.test.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/ap214_properties.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,85 @@
1
+ import fs from "fs";
2
+ import { describe, expect, test } from "@jest/globals";
3
+ import AP214StepParser from "../../AP214E3_2010/ap214_step_parser.js";
4
+ import ParsingBuffer from "../../parsing/parsing_buffer.js";
5
+ import { ParseResult } from "../../step/parsing/step_parser.js";
6
+ import { AP214Properties } from "./ap214_properties.js";
7
+ const parser = AP214StepParser.Instance;
8
+ /** web-ifc tape type code for an entity reference (a `HasProperties` handle). */
9
+ const WEB_IFC_REF_TYPE = 5;
10
+ /** Express id of the single CTC part (`product_definition`) in the fixture. */
11
+ const CTC_PRODUCT_DEFINITION_EXPRESS_ID = 4368;
12
+ /**
13
+ * Parse a hermetic STEP fixture and wrap it in an {@link AP214Properties} over a
14
+ * minimal proxy stub exposing only `StepModel` (all the spatial/property methods
15
+ * read just that).
16
+ *
17
+ * @param {string} path Fixture path.
18
+ * @return {AP214Properties} The compat surface over the parsed model.
19
+ */
20
+ function compatSurfaceFor(path) {
21
+ const buffer = fs.readFileSync(path);
22
+ const bufferInput = new ParsingBuffer(buffer);
23
+ expect(parser.parseHeader(bufferInput)[1]).toBe(ParseResult.COMPLETE);
24
+ const [result, model] = parser.parseDataToModel(bufferInput);
25
+ expect(model).not.toBe(void 0);
26
+ expect(result === ParseResult.COMPLETE || result === ParseResult.INCOMPLETE).toBe(true);
27
+ return new AP214Properties({ StepModel: model });
28
+ }
29
+ describe("compat/web-ifc/AP214Properties", () => {
30
+ test("getSpatialStructure emits Name as a web-ifc {value} handle", async () => {
31
+ const root = await compatSurfaceFor("data/as1-assembly.step").getSpatialStructure();
32
+ // Name must be { value: 'as1' } — a plain string would make Share's
33
+ // reifyName fall back to the type label, dropping the name.
34
+ expect(typeof root.Name).toBe("object");
35
+ expect(root.Name.value).toBe("as1");
36
+ expect(root.children.length).toBeGreaterThan(0);
37
+ for (const child of root.children) {
38
+ expect(child.Name.value.length).toBeGreaterThan(0);
39
+ expect(Array.isArray(child.occurrencePath)).toBe(true);
40
+ }
41
+ });
42
+ test("getItemProperties returns a {value}-wrapped identity for a node", async () => {
43
+ const surface = compatSurfaceFor("data/as1-assembly.step");
44
+ const root = await surface.getSpatialStructure();
45
+ const item = await surface.getItemProperties(root.expressID);
46
+ expect(item.expressID).toBe(root.expressID);
47
+ expect(item.Name.value).toBe("as1");
48
+ });
49
+ test("getPropertySets emits IfcPropertySet-shaped sets with reference HasProperties", async () => {
50
+ const surface = compatSurfaceFor("data/nist-ctc-properties.step");
51
+ const psets = await surface.getPropertySets(CTC_PRODUCT_DEFINITION_EXPRESS_ID);
52
+ expect(psets.length).toBeGreaterThan(0);
53
+ for (const pset of psets) {
54
+ // Set name is a {value} handle; HasProperties are reference handles
55
+ // ({type: 5, value: id}) so Share's unpackHelper can dereference them.
56
+ expect(pset.Name.value.length).toBeGreaterThan(0);
57
+ expect(pset.HasProperties.length).toBeGreaterThan(0);
58
+ for (const ref of pset.HasProperties) {
59
+ expect(ref.type).toBe(WEB_IFC_REF_TYPE);
60
+ expect(typeof ref.value).toBe("number");
61
+ }
62
+ }
63
+ });
64
+ test("a HasProperties reference resolves through getItemProperties to key/value", async () => {
65
+ const surface = compatSurfaceFor("data/nist-ctc-properties.step");
66
+ const psets = await surface.getPropertySets(CTC_PRODUCT_DEFINITION_EXPRESS_ID);
67
+ const resolved = new Map();
68
+ for (const pset of psets) {
69
+ for (const ref of pset.HasProperties) {
70
+ const prop = await surface.getItemProperties(ref.value);
71
+ expect(prop.expressID).toBe(ref.value);
72
+ resolved.set(prop.Name.value, prop.NominalValue.value);
73
+ }
74
+ }
75
+ // The NIST attribute key/values, surfaced through the reference round-trip.
76
+ expect(resolved.get("Modeled By")).toBe("Engineer");
77
+ expect(resolved.get("CAGE Code")).toBe("64JW1");
78
+ expect(resolved.get("Company")).toBe("ACME");
79
+ });
80
+ test("getPropertySets is empty for an element with no properties", async () => {
81
+ const surface = compatSurfaceFor("data/as1-assembly.step");
82
+ const root = await surface.getSpatialStructure();
83
+ expect(await surface.getPropertySets(root.expressID)).toEqual([]);
84
+ });
85
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/version/version.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,aAAa,EAAE,MAA0C,CAAA;AAG/D,OAAO,EAAC,aAAa,EAAC,CAAA"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/version/version.ts"],"names":[],"mappings":"AAOA,QAAA,MAAM,aAAa,EAAE,MAA0C,CAAA;AAG/D,OAAO,EAAC,aAAa,EAAC,CAAA"}
@@ -1,2 +1,9 @@
1
- const versionString = 'Conway Web-Ifc Shim v1.346.1102';
1
+ // Placeholder version for source/dev builds. CI's auto-publish job stamps the
2
+ // real `<major>.<PR>.<commit>` here (and into package.json) at publish time and
3
+ // does NOT commit it back to main — see .github/workflows/build.yml (auto-publish).
4
+ // So on main and in any unstamped local build this intentionally reads 1.0.0;
5
+ // only the first segment (major) is meaningful and is the one CI carries forward.
6
+ // Must stay in `vN.N.N` shape: the CI stamp regex, scripts/updateVersion.mjs, and
7
+ // statistics.ts all match `v\d+\.\d+\.\d+`.
8
+ const versionString = 'Conway Web-Ifc Shim v1.348.1109';
2
9
  export { versionString };