@ifc-lite/cli 0.33.1 → 0.36.1

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 (151) hide show
  1. package/README.md +9 -2
  2. package/dist/commands/anonymize.d.ts.map +1 -1
  3. package/dist/commands/anonymize.js +1 -0
  4. package/dist/commands/anonymize.js.map +1 -1
  5. package/dist/commands/check.d.ts +2 -0
  6. package/dist/commands/check.d.ts.map +1 -0
  7. package/dist/commands/check.js +119 -0
  8. package/dist/commands/check.js.map +1 -0
  9. package/dist/commands/convert.d.ts.map +1 -1
  10. package/dist/commands/convert.js +28 -8
  11. package/dist/commands/convert.js.map +1 -1
  12. package/dist/commands/create.d.ts.map +1 -1
  13. package/dist/commands/create.js +6 -0
  14. package/dist/commands/create.js.map +1 -1
  15. package/dist/commands/delivery-checks-rules.d.ts +37 -0
  16. package/dist/commands/delivery-checks-rules.d.ts.map +1 -0
  17. package/dist/commands/delivery-checks-rules.js +76 -0
  18. package/dist/commands/delivery-checks-rules.js.map +1 -0
  19. package/dist/commands/delivery-checks.d.ts +12 -0
  20. package/dist/commands/delivery-checks.d.ts.map +1 -1
  21. package/dist/commands/delivery-checks.js +16 -5
  22. package/dist/commands/delivery-checks.js.map +1 -1
  23. package/dist/commands/delivery-recipe.d.ts +13 -2
  24. package/dist/commands/delivery-recipe.d.ts.map +1 -1
  25. package/dist/commands/delivery-recipe.js +29 -17
  26. package/dist/commands/delivery-recipe.js.map +1 -1
  27. package/dist/commands/delivery-report.d.ts +2 -2
  28. package/dist/commands/delivery-report.d.ts.map +1 -1
  29. package/dist/commands/delivery-report.js +14 -4
  30. package/dist/commands/delivery-report.js.map +1 -1
  31. package/dist/commands/delivery.d.ts.map +1 -1
  32. package/dist/commands/delivery.js +17 -5
  33. package/dist/commands/delivery.js.map +1 -1
  34. package/dist/commands/diff-content-io.d.ts +50 -0
  35. package/dist/commands/diff-content-io.d.ts.map +1 -0
  36. package/dist/commands/diff-content-io.js +104 -0
  37. package/dist/commands/diff-content-io.js.map +1 -0
  38. package/dist/commands/diff-content-report.d.ts +23 -0
  39. package/dist/commands/diff-content-report.d.ts.map +1 -0
  40. package/dist/commands/diff-content-report.js +67 -0
  41. package/dist/commands/diff-content-report.js.map +1 -0
  42. package/dist/commands/diff-content.d.ts +19 -0
  43. package/dist/commands/diff-content.d.ts.map +1 -1
  44. package/dist/commands/diff-content.js +120 -129
  45. package/dist/commands/diff-content.js.map +1 -1
  46. package/dist/commands/diff-engine.d.ts +32 -1
  47. package/dist/commands/diff-engine.d.ts.map +1 -1
  48. package/dist/commands/diff-engine.js +76 -15
  49. package/dist/commands/diff-engine.js.map +1 -1
  50. package/dist/commands/diff-geometry.d.ts +107 -0
  51. package/dist/commands/diff-geometry.d.ts.map +1 -0
  52. package/dist/commands/diff-geometry.js +262 -0
  53. package/dist/commands/diff-geometry.js.map +1 -0
  54. package/dist/commands/diff-lineage-io.d.ts +23 -0
  55. package/dist/commands/diff-lineage-io.d.ts.map +1 -0
  56. package/dist/commands/diff-lineage-io.js +119 -0
  57. package/dist/commands/diff-lineage-io.js.map +1 -0
  58. package/dist/commands/diff-scope.d.ts.map +1 -1
  59. package/dist/commands/diff-scope.js +2 -0
  60. package/dist/commands/diff-scope.js.map +1 -1
  61. package/dist/commands/diff.d.ts.map +1 -1
  62. package/dist/commands/diff.js +36 -3
  63. package/dist/commands/diff.js.map +1 -1
  64. package/dist/commands/export.d.ts.map +1 -1
  65. package/dist/commands/export.js +13 -0
  66. package/dist/commands/export.js.map +1 -1
  67. package/dist/commands/ext.js +26 -10
  68. package/dist/commands/ext.js.map +1 -1
  69. package/dist/commands/extract-entities.d.ts.map +1 -1
  70. package/dist/commands/extract-entities.js +26 -8
  71. package/dist/commands/extract-entities.js.map +1 -1
  72. package/dist/commands/flow-tracking.d.ts +20 -0
  73. package/dist/commands/flow-tracking.d.ts.map +1 -0
  74. package/dist/commands/flow-tracking.js +86 -0
  75. package/dist/commands/flow-tracking.js.map +1 -0
  76. package/dist/commands/flow.d.ts +2 -0
  77. package/dist/commands/flow.d.ts.map +1 -0
  78. package/dist/commands/flow.js +229 -0
  79. package/dist/commands/flow.js.map +1 -0
  80. package/dist/commands/gym/channels.d.ts.map +1 -1
  81. package/dist/commands/gym/channels.js +10 -2
  82. package/dist/commands/gym/channels.js.map +1 -1
  83. package/dist/commands/gym.d.ts.map +1 -1
  84. package/dist/commands/gym.js +5 -1
  85. package/dist/commands/gym.js.map +1 -1
  86. package/dist/commands/ids.d.ts.map +1 -1
  87. package/dist/commands/ids.js +36 -3
  88. package/dist/commands/ids.js.map +1 -1
  89. package/dist/commands/info.d.ts.map +1 -1
  90. package/dist/commands/info.js +20 -5
  91. package/dist/commands/info.js.map +1 -1
  92. package/dist/commands/layer-publish.d.ts.map +1 -1
  93. package/dist/commands/layer-publish.js +6 -0
  94. package/dist/commands/layer-publish.js.map +1 -1
  95. package/dist/commands/lod.d.ts.map +1 -1
  96. package/dist/commands/lod.js +4 -1
  97. package/dist/commands/lod.js.map +1 -1
  98. package/dist/commands/mutate-step-record.d.ts +25 -1
  99. package/dist/commands/mutate-step-record.d.ts.map +1 -1
  100. package/dist/commands/mutate-step-record.js +17 -22
  101. package/dist/commands/mutate-step-record.js.map +1 -1
  102. package/dist/commands/mutate.d.ts +2 -1
  103. package/dist/commands/mutate.d.ts.map +1 -1
  104. package/dist/commands/mutate.js +27 -2
  105. package/dist/commands/mutate.js.map +1 -1
  106. package/dist/commands/rekey.d.ts +27 -0
  107. package/dist/commands/rekey.d.ts.map +1 -0
  108. package/dist/commands/rekey.js +213 -0
  109. package/dist/commands/rekey.js.map +1 -0
  110. package/dist/commands/simplify.d.ts.map +1 -1
  111. package/dist/commands/simplify.js +4 -1
  112. package/dist/commands/simplify.js.map +1 -1
  113. package/dist/commands/validate.d.ts +5 -14
  114. package/dist/commands/validate.d.ts.map +1 -1
  115. package/dist/commands/validate.js +13 -15
  116. package/dist/commands/validate.js.map +1 -1
  117. package/dist/headless-backend-store-authoring.d.ts +28 -0
  118. package/dist/headless-backend-store-authoring.d.ts.map +1 -0
  119. package/dist/headless-backend-store-authoring.js +34 -0
  120. package/dist/headless-backend-store-authoring.js.map +1 -0
  121. package/dist/headless-backend.d.ts +7 -0
  122. package/dist/headless-backend.d.ts.map +1 -1
  123. package/dist/headless-backend.js +78 -66
  124. package/dist/headless-backend.js.map +1 -1
  125. package/dist/help.d.ts +22 -0
  126. package/dist/help.d.ts.map +1 -0
  127. package/dist/help.js +260 -0
  128. package/dist/help.js.map +1 -0
  129. package/dist/index.js +45 -183
  130. package/dist/index.js.map +1 -1
  131. package/dist/loader.d.ts +2 -0
  132. package/dist/loader.d.ts.map +1 -1
  133. package/dist/loader.js +30 -1
  134. package/dist/loader.js.map +1 -1
  135. package/dist/out-flag-commands.d.ts +12 -0
  136. package/dist/out-flag-commands.d.ts.map +1 -0
  137. package/dist/out-flag-commands.js +19 -0
  138. package/dist/out-flag-commands.js.map +1 -0
  139. package/dist/query-overlay-relations.d.ts +8 -28
  140. package/dist/query-overlay-relations.d.ts.map +1 -1
  141. package/dist/query-overlay-relations.js +68 -78
  142. package/dist/query-overlay-relations.js.map +1 -1
  143. package/dist/query-overlay.d.ts +5 -3
  144. package/dist/query-overlay.d.ts.map +1 -1
  145. package/dist/query-overlay.js +57 -16
  146. package/dist/query-overlay.js.map +1 -1
  147. package/package.json +26 -22
  148. package/dist/version.d.ts +0 -14
  149. package/dist/version.d.ts.map +0 -1
  150. package/dist/version.js +0 -38
  151. package/dist/version.js.map +0 -1
@@ -27,8 +27,8 @@
27
27
  */
28
28
  import { createHash } from 'node:crypto';
29
29
  import { buildComponentFingerprints, buildDataFingerprint, } from '@ifc-lite/diff';
30
- import { RelationshipType } from '@ifc-lite/data';
31
- import { EntityExtractor, extractAllEntityAttributes, extractClassificationsOnDemand, extractProjectUnits, extractPropertiesOnDemand, extractQuantitiesOnDemand, getAttributeNamesAcrossSchemas, quantitySiScale, roundToScale, scaledPropertyValue, } from '@ifc-lite/parser';
30
+ import { RelationshipType, resolvedTypeName } from '@ifc-lite/data';
31
+ import { EntityExtractor, extractAllEntityAttributes, extractClassificationsOnDemand, extractProjectUnits, extractPropertiesOnDemand, extractQuantitiesOnDemand, authoredKeyValue, getAttributeNamesAcrossSchemas, parseAuthoredKeySpec, spatialContainerPath, quantitySiScale, roundToScale, scaledPropertyValue, } from '@ifc-lite/parser';
32
32
  import { classificationLabel } from './diff-classification-label.js';
33
33
  import { comparableEntities } from './diff-scope.js';
34
34
  /**
@@ -42,16 +42,46 @@ export function modelIdentityOf(path, bytes) {
42
42
  const digest = createHash('sha256').update(bytes).digest('hex');
43
43
  return { hash: `sha256:${digest}`, path };
44
44
  }
45
+ /** Prefix on a fingerprint key taken from an authored property rather than a GlobalId. */
46
+ export const AUTHORED_KEY_PREFIX = 'prop:';
45
47
  /**
46
- * Build one {@link EntityFingerprint} per `IfcObjectDefinition` in a store.
47
- *
48
- * `components` is populated as well as `dataHash`: the content pass's only
49
- * defence against a `dataHash` collision retiring an unrelated add/delete pair
50
- * is agreement on `ifcType` and on every component sub-hash, and the second
51
- * check is inert unless both sides supply them (see the "Hash collisions"
52
- * section of `docs/guide/model-diff.md`).
48
+ * Resolve every entity's key under an authored-key spec: `prop:<value>` where
49
+ * the value is present and unique, GlobalId otherwise. Duplicates are reported
50
+ * to the caller rather than silently collapsed by `indexByKey`.
53
51
  */
54
- export function buildFileFingerprints(store) {
52
+ export function resolveAuthoredKeys(store, entities, options) {
53
+ const keys = new Map();
54
+ const spec = options.keyProperty ? parseAuthoredKeySpec(options.keyProperty) : undefined;
55
+ if (!spec) {
56
+ for (const { expressId, globalId } of entities)
57
+ keys.set(expressId, globalId);
58
+ return keys;
59
+ }
60
+ const extractor = new EntityExtractor(store.source);
61
+ const owners = new Map();
62
+ for (const { expressId } of entities) {
63
+ const value = authoredKeyValue(store, expressId, spec, extractor);
64
+ if (value === undefined)
65
+ continue;
66
+ const list = owners.get(value);
67
+ if (list)
68
+ list.push(expressId);
69
+ else
70
+ owners.set(value, [expressId]);
71
+ }
72
+ for (const { expressId, globalId } of entities)
73
+ keys.set(expressId, globalId);
74
+ for (const [value, ids] of owners) {
75
+ if (ids.length === 1) {
76
+ keys.set(ids[0], `${AUTHORED_KEY_PREFIX}${value}`);
77
+ }
78
+ else {
79
+ options.duplicateAuthoredKeys?.set(value, ids);
80
+ }
81
+ }
82
+ return keys;
83
+ }
84
+ export function buildFileFingerprints(store, options = {}) {
55
85
  // Resolved once per store, not per entity: the same `IFCUNITASSIGNMENT` walk
56
86
  // every property in the file would otherwise repeat, and both `quantitySiScale`
57
87
  // and `scaleMeasureValue` are pure over it. An IfcQuantityLength/Area/Volume
@@ -61,19 +91,49 @@ export function buildFileFingerprints(store) {
61
91
  // physical quantity actually changed, reports every quantified/measured
62
92
  // entity as `modified` (see `buildDataInput`'s scaling comment).
63
93
  const units = extractProjectUnits(store.source, store.entityIndex);
94
+ const entities = [...comparableEntities(store)];
95
+ const keys = resolveAuthoredKeys(store, entities, options);
64
96
  const fingerprints = [];
65
- for (const { expressId, globalId, ifcType, source, isTypeObject } of comparableEntities(store)) {
97
+ for (const { expressId, globalId, ifcType, source, isTypeObject } of entities) {
66
98
  const input = buildDataInput(store, expressId, ifcType, source, isTypeObject, units);
67
- fingerprints.push({
68
- key: globalId,
99
+ const fingerprint = {
100
+ key: keys.get(expressId) ?? globalId,
69
101
  ifcType,
70
102
  dataHash: buildDataFingerprint(input),
71
103
  components: buildComponentFingerprints(input),
72
104
  ref: expressId,
73
- });
105
+ };
106
+ // Where the element sits, as a name path (issue #4955). Read for every
107
+ // entity even though only the successor stage consumes it: the adapter
108
+ // does not know which stages the caller will run.
109
+ const container = spatialContainerPath(store, expressId);
110
+ if (container !== undefined)
111
+ fingerprint.container = container;
112
+ fingerprints.push(fingerprint);
74
113
  }
75
114
  return fingerprints;
76
115
  }
116
+ /** A collision discovered in either file invalidates that authored value in
117
+ * both files, including fingerprints already built for the first side. */
118
+ export function fallbackPairDuplicateAuthoredKeys(sides, duplicates) {
119
+ if (duplicates.size === 0)
120
+ return;
121
+ for (const { fingerprints, store } of sides) {
122
+ const globalIds = new Map([...comparableEntities(store)].map((entity) => [entity.expressId, entity.globalId]));
123
+ for (const fingerprint of fingerprints) {
124
+ if (!fingerprint.key.startsWith(AUTHORED_KEY_PREFIX))
125
+ continue;
126
+ const value = fingerprint.key.slice(AUTHORED_KEY_PREFIX.length);
127
+ if (!duplicates.has(value))
128
+ continue;
129
+ const globalId = globalIds.get(fingerprint.ref);
130
+ if (!globalId) {
131
+ throw new Error(`Cannot restore GlobalId for authored-key collision on #${fingerprint.ref}`);
132
+ }
133
+ fingerprint.key = globalId;
134
+ }
135
+ }
136
+ }
77
137
  /**
78
138
  * Assemble the canonical {@link DataFingerprintInput} for one entity.
79
139
  *
@@ -125,7 +185,7 @@ units) {
125
185
  .map((typeId) => ({
126
186
  globalId: store.entities.getGlobalId(typeId) || undefined,
127
187
  name: store.entities.getName(typeId) || undefined,
128
- type: store.entities.getTypeName(typeId) || undefined,
188
+ type: resolvedTypeName(store.entities, typeId),
129
189
  }));
130
190
  // Resolved classification references (never entity references — see
131
191
  // `DataFingerprintInput.classifications`): an `IfcRelAssociatesClassification`
@@ -172,6 +232,7 @@ function attributeAcrossSchemas(store, expressId, ifcType, attributeName) {
172
232
  const index = getAttributeNamesAcrossSchemas(ifcType).indexOf(attributeName);
173
233
  if (index < 0)
174
234
  return undefined;
235
+ // @raw-entity-enumeration-ok the CLI fingerprint hashes a source STEP slot from a freshly loaded file
175
236
  const ref = store.entityIndex.byId.get(expressId);
176
237
  if (!ref)
177
238
  return undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"diff-engine.js","sourceRoot":"","sources":["../../src/commands/diff-engine.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,0BAA0B,EAC1B,oBAAoB,GAIrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EACL,eAAe,EACf,0BAA0B,EAC1B,8BAA8B,EAC9B,mBAAmB,EACnB,yBAAyB,EACzB,yBAAyB,EACzB,8BAA8B,EAC9B,eAAe,EACf,YAAY,EACZ,mBAAmB,GAGpB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAuB,MAAM,iBAAiB,CAAC;AAK1E;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,KAAiB;IAC7D,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChE,OAAO,EAAE,IAAI,EAAE,UAAU,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAmB;IACvD,6EAA6E;IAC7E,gFAAgF;IAChF,6EAA6E;IAC7E,2EAA2E;IAC3E,sEAAsE;IACtE,4EAA4E;IAC5E,wEAAwE;IACxE,iEAAiE;IACjE,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;IACnE,MAAM,YAAY,GAAiC,EAAE,CAAC;IACtD,KAAK,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/F,MAAM,KAAK,GAAG,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;QACrF,YAAY,CAAC,IAAI,CAAC;YAChB,GAAG,EAAE,QAAQ;YACb,OAAO;YACP,QAAQ,EAAE,oBAAoB,CAAC,KAAK,CAAC;YACrC,UAAU,EAAE,0BAA0B,CAAC,KAAK,CAAC;YAC7C,GAAG,EAAE,SAAS;SACf,CAAC,CAAC;IACL,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,cAAc,CACrB,KAAmB,EACnB,SAAiB,EACjB,OAAe;AACf;4DAC4D;AAC5D,MAAkC;AAClC,+EAA+E;AAC/E,YAAqB;AACrB;;4CAE4C;AAC5C,KAAmB;IAEnB,MAAM,cAAc,GAAG,0BAA0B,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,IAAI,CACtE,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,gBAAgB,CACnD,EAAE,KAAK,CAAC;IACT,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhG,MAAM,YAAY,GAAG,yBAAyB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7E,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC5C,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,KAAK,EAAE,mBAAmB,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;SACrE,CAAC,CAAC;KACJ,CAAC,CAAC,CAAC;IAEJ,MAAM,YAAY,GAAG,yBAAyB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7E,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC5C,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,qEAAqE;YACrE,2CAA2C;YAC3C,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,KAAK,GAAG,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;SACvE,CAAC,CAAC;KACJ,CAAC,CAAC,CAAC;IAEJ,MAAM,eAAe,GAAG,KAAK,CAAC,aAAa;SACxC,UAAU,CAAC,SAAS,EAAE,gBAAgB,CAAC,aAAa,EAAE,SAAS,CAAC;SAChE,GAAG,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;QACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,SAAS;QACzD,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,SAAS;QACjD,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,SAAS;KACtD,CAAC,CAAC,CAAC;IAEN,oEAAoE;IACpE,+EAA+E;IAC/E,6EAA6E;IAC7E,mEAAmE;IACnE,MAAM,eAAe,GAAG,8BAA8B,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAElG,OAAO;QACL,OAAO;QACP,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,MAAM,EAAE,IAAI,IAAI,SAAS;QACpE,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,MAAM,EAAE,WAAW,IAAI,SAAS;QACzF,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,MAAM,EAAE,UAAU,IAAI,SAAS;QACtF,cAAc,EAAE,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS;QAC3E,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC1C,YAAY;QACZ,YAAY;QACZ,eAAe;QACf,eAAe;KAChB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAS,sBAAsB,CAC7B,KAAmB,EACnB,SAAiB,EACjB,OAAe,EACf,aAAqB;IAErB,MAAM,KAAK,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAC7E,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAClD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC;IACtF,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACtF,CAAC"}
1
+ {"version":3,"file":"diff-engine.js","sourceRoot":"","sources":["../../src/commands/diff-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import type { DiffScope, EntityFingerprint } from '@ifc-lite/diff';
2
+ import type { IfcAPI as WasmIfcAPI } from '@ifc-lite/wasm';
3
+ import type { DiffRef } from './diff-engine.js';
4
+ /** Quantization grid for the geometry hash, in metres — the wasm default
5
+ * (`DEFAULT_GEOM_HASH_TOLERANCE` in `@ifc-lite/geometry`), restated here so
6
+ * this module has no runtime dependency on that package. */
7
+ export declare const GEOMETRY_HASH_TOLERANCE = 0.001;
8
+ /** Printed (CLI) or returned (adapters) when `--geometry` cannot run because
9
+ * the wasm runtime is not built on this host — the `.wasm` binary is
10
+ * gitignored and only present after a Rust-capable build. */
11
+ export declare const WASM_RUNTIME_ABSENT_MESSAGE: string;
12
+ export interface WasmRuntime {
13
+ api: WasmIfcAPI;
14
+ }
15
+ export type WasmRuntimeResult = {
16
+ ok: true;
17
+ runtime: WasmRuntime;
18
+ } | {
19
+ ok: false;
20
+ message: string;
21
+ };
22
+ /**
23
+ * Lazily load and initialize `@ifc-lite/wasm`, returning a ready `IfcAPI` with
24
+ * geometry hashing switched on.
25
+ *
26
+ * Never throws: a missing `.wasm` binary, a missing package resolution, or an
27
+ * init failure all come back as `{ ok: false, message }` so the caller can
28
+ * report a clear, actionable message instead of a raw stack trace. Not
29
+ * memoised — the caller owns the returned `IfcAPI` and must `.free()` it
30
+ * (issue #4956, AGENTS.md "Geometry & WASM").
31
+ */
32
+ export declare function loadWasmRuntime(): Promise<WasmRuntimeResult>;
33
+ export interface GeometryAabb {
34
+ readonly min: readonly [number, number, number];
35
+ readonly max: readonly [number, number, number];
36
+ }
37
+ /** Per-entity world geometry hashes, boxes and volumes from one wasm mesh
38
+ * pass, keyed by express id. */
39
+ export interface GeometryPassResult {
40
+ hashes: Map<DiffRef, bigint>;
41
+ aabbs: Map<DiffRef, GeometryAabb>;
42
+ volumes: Map<DiffRef, number>;
43
+ unitScale: number;
44
+ }
45
+ /**
46
+ * Run the wasm geometry pass over one file's bytes and collect per-entity
47
+ * world hashes, boxes and volumes (issue #4956).
48
+ *
49
+ * Ported from `scripts/xmatch/fingerprints.mjs`'s `geometryPass` — see that
50
+ * file's history for why each guard exists: a box with a non-finite
51
+ * coordinate is dropped rather than passed on (a present box must be usable,
52
+ * never a NaN the engine would classify as garbage), and a volume is kept
53
+ * only when finite and positive (`NaN` is the wasm's "not proved closed"
54
+ * sentinel).
55
+ *
56
+ * **Chunked, not one `processGeometryBatch` call over every job.** The naive
57
+ * one-shot version materializes every mesh of the whole file into a single
58
+ * `MeshCollection` before any hash is read, which OOMs on a large model
59
+ * (issue #4956 review) — the same reason the browser worker path never does
60
+ * this either (`@ifc-lite/geometry`'s `processStreamingBytes`, `batch-sizing.ts`).
61
+ * Each `JOBS_PER_BATCH`-sized slice gets its own `MeshCollection`, is read and
62
+ * freed, and only its extracted (hash, aabb, volume) triples survive into the
63
+ * next iteration.
64
+ *
65
+ * The pre-pass call is inside the same `try` the cache-clear `finally`
66
+ * guards: `buildPrePassOnce` can itself throw (a malformed file), and a throw
67
+ * before the `try` would skip `clearPrePassCache()`, carrying whatever partial
68
+ * state it left behind into the next file processed through this `api`.
69
+ *
70
+ * **Installs the source once, rather than passing `bytes` to every chunk's
71
+ * `processGeometryBatch` call.** The legacy call takes `data` positionally and
72
+ * copies it into wasm linear memory on every invocation — fine for one call,
73
+ * but `JOBS_PER_BATCH`-chunking turns that into hundreds of copies of the
74
+ * whole file for a large model (issue #4956 review). `setSourceBytes` +
75
+ * `processGeometryBatchFromSource` is the same lever the browser worker's
76
+ * cold-load path uses (`geometry.worker.ts`'s `applySourceBytesToApi` /
77
+ * `batchFromSourceFn`): install the file ONCE, then every chunk reads it off
78
+ * the wasm heap. Feature-detected — a wasm build that predates the `*FromSource`
79
+ * pair falls back to the legacy per-call `bytes` argument.
80
+ */
81
+ export declare function runGeometryPass(api: WasmIfcAPI, bytes: Uint8Array): GeometryPassResult;
82
+ /**
83
+ * Attach one file's geometry pass onto the fingerprints already built for it
84
+ * (mutates in place — the fingerprints are freshly built per file, never
85
+ * shared, so this is not a hazard).
86
+ */
87
+ export declare function attachGeometryFingerprints(fingerprints: readonly EntityFingerprint<DiffRef>[], geometry: GeometryPassResult): void;
88
+ /**
89
+ * The whole `--geometry` opt-in, as one call for `diff-content.ts`: lazily
90
+ * load the runtime, run the pass over both files, attach it to both sets of
91
+ * fingerprints, and report the resulting {@link DiffScope}. A missing runtime
92
+ * is reported through `warn` (a stderr line, not a thrown error) and the
93
+ * scope falls back to `'data'` — the rest of `--by-content` works fine
94
+ * without geometry, exactly as it always has.
95
+ *
96
+ * Frees the `IfcAPI` handle in `finally`, even if a pass throws (AGENTS.md
97
+ * "Geometry & WASM"). A pass that throws — a malformed or truncated model,
98
+ * or an internal wasm panic surfaced as a JS error — degrades to `'data'`
99
+ * scope with a warning rather than aborting the whole `--by-content` command
100
+ * (issue #4956 review): `--geometry` is opt-in extra evidence, and the
101
+ * data-only comparison underneath it is still a useful answer. Any
102
+ * `geometryHash`/`aabb`/`volume` a partial pass DID manage to attach before
103
+ * throwing is harmless left attached — `scope: 'data'` takes geometry out of
104
+ * the comparison regardless of what individual fingerprints carry.
105
+ */
106
+ export declare function resolveGeometryScope(enabled: boolean, baseBytes: Uint8Array, headBytes: Uint8Array, baseFingerprints: readonly EntityFingerprint<DiffRef>[], headFingerprints: readonly EntityFingerprint<DiffRef>[], warn: (message: string) => void): Promise<DiffScope>;
107
+ //# sourceMappingURL=diff-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-geometry.d.ts","sourceRoot":"","sources":["../../src/commands/diff-geometry.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD;;6DAE6D;AAC7D,eAAO,MAAM,uBAAuB,QAAO,CAAC;AAE5C;;8DAE8D;AAC9D,eAAO,MAAM,2BAA2B,QAGsC,CAAC;AAE/E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,UAAU,CAAC;CACjB;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,GAClC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC;;;;;;;;;GASG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAmClE;AAuBD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACjD;AAED;iCACiC;AACjC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAClC,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,kBAAkB,CAuGtF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAAE,EACnD,QAAQ,EAAE,kBAAkB,GAC3B,IAAI,CASN;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,UAAU,EACrB,SAAS,EAAE,UAAU,EACrB,gBAAgB,EAAE,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAAE,EACvD,gBAAgB,EAAE,SAAS,iBAAiB,CAAC,OAAO,CAAC,EAAE,EACvD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAC9B,OAAO,CAAC,SAAS,CAAC,CAiBpB"}
@@ -0,0 +1,262 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * The `--geometry` half of `ifc-lite diff --by-content` (issue #4956).
6
+ *
7
+ * `diff-engine.ts` builds DATA-scope fingerprints only — the Node CLI has no
8
+ * geometry pipeline of its own, so every geometry-backed tier of
9
+ * `@ifc-lite/diff` (`renamed` on world geometry hash, `moved`/`reshaped`,
10
+ * split/merge, successors) abstains under `scope: 'data'`. This module is the
11
+ * missing pipeline: it loads `@ifc-lite/wasm` LAZILY (only when `--geometry` is
12
+ * passed — most invocations of this command never touch wasm at all), runs the
13
+ * same mesh pass the viewer's compare uses (`setComputeGeometryHashes` +
14
+ * `buildPrePassOnce` + `processGeometryBatch`), and attaches `geometryHash`,
15
+ * `aabb` and `volume` to fingerprints the caller already built.
16
+ *
17
+ * `scripts/xmatch/fingerprints.mjs` imports this module's compiled output
18
+ * rather than re-implementing the pass — see that file's header.
19
+ */
20
+ import { createRequire } from 'node:module';
21
+ import { readFile } from 'node:fs/promises';
22
+ /** Quantization grid for the geometry hash, in metres — the wasm default
23
+ * (`DEFAULT_GEOM_HASH_TOLERANCE` in `@ifc-lite/geometry`), restated here so
24
+ * this module has no runtime dependency on that package. */
25
+ export const GEOMETRY_HASH_TOLERANCE = 1e-3;
26
+ /** Printed (CLI) or returned (adapters) when `--geometry` cannot run because
27
+ * the wasm runtime is not built on this host — the `.wasm` binary is
28
+ * gitignored and only present after a Rust-capable build. */
29
+ export const WASM_RUNTIME_ABSENT_MESSAGE = '--geometry requires the @ifc-lite/wasm runtime, which is not built on this host ' +
30
+ '(packages/wasm/pkg/ifc-lite_bg.wasm is missing). Run `pnpm build:wasm:fetch` to fetch ' +
31
+ 'a prebuilt binary, or `pnpm build:wasm` with the Rust toolchain installed.';
32
+ /**
33
+ * Lazily load and initialize `@ifc-lite/wasm`, returning a ready `IfcAPI` with
34
+ * geometry hashing switched on.
35
+ *
36
+ * Never throws: a missing `.wasm` binary, a missing package resolution, or an
37
+ * init failure all come back as `{ ok: false, message }` so the caller can
38
+ * report a clear, actionable message instead of a raw stack trace. Not
39
+ * memoised — the caller owns the returned `IfcAPI` and must `.free()` it
40
+ * (issue #4956, AGENTS.md "Geometry & WASM").
41
+ */
42
+ export async function loadWasmRuntime() {
43
+ let wasmPath;
44
+ try {
45
+ wasmPath = createRequire(import.meta.url).resolve('@ifc-lite/wasm/ifc-lite_bg.wasm');
46
+ }
47
+ catch {
48
+ return { ok: false, message: WASM_RUNTIME_ABSENT_MESSAGE };
49
+ }
50
+ let bytes;
51
+ try {
52
+ bytes = await readFile(wasmPath);
53
+ }
54
+ catch {
55
+ return { ok: false, message: WASM_RUNTIME_ABSENT_MESSAGE };
56
+ }
57
+ try {
58
+ const wasmModule = await import('@ifc-lite/wasm');
59
+ wasmModule.initSync({ module: bytes });
60
+ // Constructed before the next call that can throw, so a failure past this
61
+ // point has a handle to free rather than leaking it (AGENTS.md "Geometry
62
+ // & WASM").
63
+ const api = new wasmModule.IfcAPI();
64
+ try {
65
+ api.setComputeGeometryHashes(GEOMETRY_HASH_TOLERANCE);
66
+ }
67
+ catch (error) {
68
+ api.free();
69
+ throw error;
70
+ }
71
+ return { ok: true, runtime: { api } };
72
+ }
73
+ catch (error) {
74
+ return {
75
+ ok: false,
76
+ message: `${WASM_RUNTIME_ABSENT_MESSAGE} (init failed: ${error.message})`,
77
+ };
78
+ }
79
+ }
80
+ /**
81
+ * Number of jobs sent to one `processGeometryBatch` call.
82
+ *
83
+ * Matches `DEFAULT_BATCH_SIZING.maxJobs` in `@ifc-lite/geometry`'s
84
+ * `batch-sizing.ts` — the cap the browser worker's adaptive sizer clamps every
85
+ * call to, tuned on the largest real models so one call's meshes stay a
86
+ * bounded slice of the file rather than the whole thing. Restated here
87
+ * (rather than imported) because that module is internal to the geometry
88
+ * worker's streaming path and not part of `@ifc-lite/geometry`'s public
89
+ * surface; kept in sync by citing the source. This path has no adaptive
90
+ * timing to resize it (a one-shot CLI pass, not a watchdog-bounded worker), so
91
+ * it is a fixed cap rather than the worker's targetMs-driven adaptive size.
92
+ */
93
+ const JOBS_PER_BATCH = 512;
94
+ /** Uint32 slots per job in `PrePassResult.jobs` — see `prePass.jobs.slice(startJob
95
+ * * JOB_STRIDE, endJob * JOB_STRIDE)` in `@ifc-lite/geometry`'s `processStreamingBytes`. */
96
+ const JOB_STRIDE = 3;
97
+ /**
98
+ * Run the wasm geometry pass over one file's bytes and collect per-entity
99
+ * world hashes, boxes and volumes (issue #4956).
100
+ *
101
+ * Ported from `scripts/xmatch/fingerprints.mjs`'s `geometryPass` — see that
102
+ * file's history for why each guard exists: a box with a non-finite
103
+ * coordinate is dropped rather than passed on (a present box must be usable,
104
+ * never a NaN the engine would classify as garbage), and a volume is kept
105
+ * only when finite and positive (`NaN` is the wasm's "not proved closed"
106
+ * sentinel).
107
+ *
108
+ * **Chunked, not one `processGeometryBatch` call over every job.** The naive
109
+ * one-shot version materializes every mesh of the whole file into a single
110
+ * `MeshCollection` before any hash is read, which OOMs on a large model
111
+ * (issue #4956 review) — the same reason the browser worker path never does
112
+ * this either (`@ifc-lite/geometry`'s `processStreamingBytes`, `batch-sizing.ts`).
113
+ * Each `JOBS_PER_BATCH`-sized slice gets its own `MeshCollection`, is read and
114
+ * freed, and only its extracted (hash, aabb, volume) triples survive into the
115
+ * next iteration.
116
+ *
117
+ * The pre-pass call is inside the same `try` the cache-clear `finally`
118
+ * guards: `buildPrePassOnce` can itself throw (a malformed file), and a throw
119
+ * before the `try` would skip `clearPrePassCache()`, carrying whatever partial
120
+ * state it left behind into the next file processed through this `api`.
121
+ *
122
+ * **Installs the source once, rather than passing `bytes` to every chunk's
123
+ * `processGeometryBatch` call.** The legacy call takes `data` positionally and
124
+ * copies it into wasm linear memory on every invocation — fine for one call,
125
+ * but `JOBS_PER_BATCH`-chunking turns that into hundreds of copies of the
126
+ * whole file for a large model (issue #4956 review). `setSourceBytes` +
127
+ * `processGeometryBatchFromSource` is the same lever the browser worker's
128
+ * cold-load path uses (`geometry.worker.ts`'s `applySourceBytesToApi` /
129
+ * `batchFromSourceFn`): install the file ONCE, then every chunk reads it off
130
+ * the wasm heap. Feature-detected — a wasm build that predates the `*FromSource`
131
+ * pair falls back to the legacy per-call `bytes` argument.
132
+ */
133
+ export function runGeometryPass(api, bytes) {
134
+ const hashes = new Map();
135
+ const aabbs = new Map();
136
+ const volumes = new Map();
137
+ let unitScale = 1;
138
+ const useSource = typeof api.setSourceBytes === 'function' &&
139
+ typeof api.processGeometryBatchFromSource === 'function';
140
+ if (useSource)
141
+ api.setSourceBytes(bytes);
142
+ try {
143
+ const pre = api.buildPrePassOnce(bytes);
144
+ unitScale = pre?.unitScale ?? 1;
145
+ const total = pre?.totalJobs ?? 0;
146
+ if (!pre || !pre.jobs || total === 0)
147
+ return { hashes, aabbs, volumes, unitScale };
148
+ const rtcOffset = pre.rtcOffset ? Array.from(pre.rtcOffset) : [0, 0, 0];
149
+ const [rtcX, rtcY, rtcZ] = rtcOffset;
150
+ const voidKeys = pre.voidKeys ?? new Uint32Array(0);
151
+ const voidCounts = pre.voidCounts ?? new Uint32Array(0);
152
+ const voidValues = pre.voidValues ?? new Uint32Array(0);
153
+ const styleIds = pre.styleIds ?? new Uint32Array(0);
154
+ const styleColors = pre.styleColors ?? new Uint8Array(0);
155
+ for (let startJob = 0; startJob < total; startJob += JOBS_PER_BATCH) {
156
+ const endJob = Math.min(startJob + JOBS_PER_BATCH, total);
157
+ const jobSlice = pre.jobs.slice(startJob * JOB_STRIDE, endJob * JOB_STRIDE);
158
+ const collection = useSource
159
+ ? api.processGeometryBatchFromSource(jobSlice, pre.unitScale ?? 1, rtcX, rtcY, rtcZ, pre.needsShift ?? false, voidKeys, voidCounts, voidValues, styleIds, styleColors, pre.planeAngleToRadians, pre.materialElementIds, pre.materialColorCounts, pre.materialColors)
160
+ : api.processGeometryBatch(bytes, jobSlice, pre.unitScale ?? 1, rtcX, rtcY, rtcZ, pre.needsShift ?? false, voidKeys, voidCounts, voidValues, styleIds, styleColors, pre.planeAngleToRadians, pre.materialElementIds, pre.materialColorCounts, pre.materialColors);
161
+ try {
162
+ const ids = collection.geometryHashIds;
163
+ const values = collection.geometryHashValues;
164
+ const boxes = collection.geometryAabbValues;
165
+ // Optional getter (issue #4955): a wasm build that predates it
166
+ // answers `undefined`, and volumes simply stay empty rather than
167
+ // throwing.
168
+ const volumeValues = collection.geometryVolumeValues;
169
+ for (let i = 0; i < ids.length; i++) {
170
+ hashes.set(ids[i], values[i]);
171
+ const volume = volumeValues?.[i];
172
+ if (volume !== undefined && Number.isFinite(volume) && volume > 0) {
173
+ volumes.set(ids[i], volume);
174
+ }
175
+ // Same optional-getter rule as volumes: no boxes, keep the hashes.
176
+ const box = boxes ? Array.from(boxes.slice(6 * i, 6 * i + 6)) : [];
177
+ if (box.length === 6 && box.every((value) => Number.isFinite(value))) {
178
+ aabbs.set(ids[i], {
179
+ min: [box[0], box[1], box[2]],
180
+ max: [box[3], box[4], box[5]],
181
+ });
182
+ }
183
+ }
184
+ }
185
+ finally {
186
+ // Freed before the next chunk's call, not batched up with the rest —
187
+ // this is the whole point of chunking: at most one batch's meshes
188
+ // are live in wasm memory at a time.
189
+ collection.free();
190
+ }
191
+ }
192
+ }
193
+ finally {
194
+ if (api.clearPrePassCache)
195
+ api.clearPrePassCache();
196
+ // `setSourceBytes` "REPLACES the previous file wholesale" (its own doc
197
+ // comment) — there is no dedicated release call, so installing an empty
198
+ // buffer is how this drops its reference to a possibly large file instead
199
+ // of leaving it resident on the wasm heap for the rest of the process.
200
+ if (useSource)
201
+ api.setSourceBytes(new Uint8Array(0));
202
+ }
203
+ return { hashes, aabbs, volumes, unitScale };
204
+ }
205
+ /**
206
+ * Attach one file's geometry pass onto the fingerprints already built for it
207
+ * (mutates in place — the fingerprints are freshly built per file, never
208
+ * shared, so this is not a hazard).
209
+ */
210
+ export function attachGeometryFingerprints(fingerprints, geometry) {
211
+ for (const fingerprint of fingerprints) {
212
+ const hash = geometry.hashes.get(fingerprint.ref);
213
+ if (hash !== undefined)
214
+ fingerprint.geometryHash = hash;
215
+ const aabb = geometry.aabbs.get(fingerprint.ref);
216
+ if (aabb !== undefined)
217
+ fingerprint.aabb = aabb;
218
+ const volume = geometry.volumes.get(fingerprint.ref);
219
+ if (volume !== undefined)
220
+ fingerprint.volume = volume;
221
+ }
222
+ }
223
+ /**
224
+ * The whole `--geometry` opt-in, as one call for `diff-content.ts`: lazily
225
+ * load the runtime, run the pass over both files, attach it to both sets of
226
+ * fingerprints, and report the resulting {@link DiffScope}. A missing runtime
227
+ * is reported through `warn` (a stderr line, not a thrown error) and the
228
+ * scope falls back to `'data'` — the rest of `--by-content` works fine
229
+ * without geometry, exactly as it always has.
230
+ *
231
+ * Frees the `IfcAPI` handle in `finally`, even if a pass throws (AGENTS.md
232
+ * "Geometry & WASM"). A pass that throws — a malformed or truncated model,
233
+ * or an internal wasm panic surfaced as a JS error — degrades to `'data'`
234
+ * scope with a warning rather than aborting the whole `--by-content` command
235
+ * (issue #4956 review): `--geometry` is opt-in extra evidence, and the
236
+ * data-only comparison underneath it is still a useful answer. Any
237
+ * `geometryHash`/`aabb`/`volume` a partial pass DID manage to attach before
238
+ * throwing is harmless left attached — `scope: 'data'` takes geometry out of
239
+ * the comparison regardless of what individual fingerprints carry.
240
+ */
241
+ export async function resolveGeometryScope(enabled, baseBytes, headBytes, baseFingerprints, headFingerprints, warn) {
242
+ if (!enabled)
243
+ return 'data';
244
+ const runtime = await loadWasmRuntime();
245
+ if (!runtime.ok) {
246
+ warn(runtime.message);
247
+ return 'data';
248
+ }
249
+ try {
250
+ attachGeometryFingerprints(baseFingerprints, runGeometryPass(runtime.runtime.api, baseBytes));
251
+ attachGeometryFingerprints(headFingerprints, runGeometryPass(runtime.runtime.api, headBytes));
252
+ return 'both';
253
+ }
254
+ catch (error) {
255
+ warn(`--geometry failed (${error.message}); continuing with data scope.`);
256
+ return 'data';
257
+ }
258
+ finally {
259
+ runtime.runtime.api.free();
260
+ }
261
+ }
262
+ //# sourceMappingURL=diff-geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-geometry.js","sourceRoot":"","sources":["../../src/commands/diff-geometry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type IdentityMapSidecar, type LineageEntry, type LineageSidecar, type ModelDiff, type ModelIdentity } from '@ifc-lite/diff';
2
+ import type { DiffRef } from './diff-engine.js';
3
+ /** Union of two alias maps; a head key the two disagree about is dropped. */
4
+ export declare function mergeAliases(a: Map<string, string> | undefined, b: Map<string, string> | undefined): Map<string, string> | undefined;
5
+ /**
6
+ * The lineage the output should carry: every entry this run derived (committed
7
+ * matches, plus `replaced` from the accepted map), with the incoming lineage's
8
+ * own provenance preserved on the aliases that still applied. Split/merge
9
+ * entries an earlier geometry-capable run wrote are carried forward verbatim
10
+ * when every key they name is still absent from this run's 1:1 answers — this
11
+ * data-scope run cannot re-derive or refute them, and dropping them would make
12
+ * a CLI round trip erase what the viewer established.
13
+ */
14
+ export declare function mergeLineage(incomingLineage: LineageSidecar | undefined, incomingMap: IdentityMapSidecar | undefined, diff: ModelDiff<DiffRef>, accepted: IdentityMapSidecar | undefined): {
15
+ entries: LineageEntry[];
16
+ deleted: string[];
17
+ };
18
+ export declare function readVerifiedLineage(path: string, models: {
19
+ base: ModelIdentity;
20
+ head: ModelIdentity;
21
+ keyProperty?: string;
22
+ }): Promise<LineageSidecar>;
23
+ //# sourceMappingURL=diff-lineage-io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-lineage-io.d.ts","sourceRoot":"","sources":["../../src/commands/diff-lineage-io.ts"],"names":[],"mappings":"AAYA,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,6EAA6E;AAC7E,wBAAgB,YAAY,CAC1B,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAClC,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GACjC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAUjC;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,eAAe,EAAE,cAAc,GAAG,SAAS,EAC3C,WAAW,EAAE,kBAAkB,GAAG,SAAS,EAC3C,IAAI,EAAE,SAAS,CAAC,OAAO,CAAC,EACxB,QAAQ,EAAE,kBAAkB,GAAG,SAAS,GACvC;IAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAqDhD;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,aAAa,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE,OAAO,CAAC,cAAc,CAAC,CAkBzB"}