@ifc-lite/cli 0.26.0 → 0.28.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.
Files changed (146) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/ask.d.ts +8 -0
  3. package/dist/commands/ask.d.ts.map +1 -1
  4. package/dist/commands/ask.js +10 -9
  5. package/dist/commands/ask.js.map +1 -1
  6. package/dist/commands/bsdd.d.ts.map +1 -1
  7. package/dist/commands/bsdd.js +49 -13
  8. package/dist/commands/bsdd.js.map +1 -1
  9. package/dist/commands/delivery-checks.d.ts +56 -0
  10. package/dist/commands/delivery-checks.d.ts.map +1 -0
  11. package/dist/commands/delivery-checks.js +222 -0
  12. package/dist/commands/delivery-checks.js.map +1 -0
  13. package/dist/commands/delivery-recipe.d.ts +23 -0
  14. package/dist/commands/delivery-recipe.d.ts.map +1 -0
  15. package/dist/commands/delivery-recipe.js +104 -0
  16. package/dist/commands/delivery-recipe.js.map +1 -0
  17. package/dist/commands/delivery-report.d.ts +51 -0
  18. package/dist/commands/delivery-report.d.ts.map +1 -0
  19. package/dist/commands/delivery-report.js +114 -0
  20. package/dist/commands/delivery-report.js.map +1 -0
  21. package/dist/commands/delivery.d.ts +2 -0
  22. package/dist/commands/delivery.d.ts.map +1 -0
  23. package/dist/commands/delivery.js +127 -0
  24. package/dist/commands/delivery.js.map +1 -0
  25. package/dist/commands/diff-classification-label.d.ts +12 -0
  26. package/dist/commands/diff-classification-label.d.ts.map +1 -0
  27. package/dist/commands/diff-classification-label.js +20 -0
  28. package/dist/commands/diff-classification-label.js.map +1 -0
  29. package/dist/commands/diff-engine.d.ts.map +1 -1
  30. package/dist/commands/diff-engine.js +33 -11
  31. package/dist/commands/diff-engine.js.map +1 -1
  32. package/dist/commands/diff-test-helpers.d.ts +12 -0
  33. package/dist/commands/diff-test-helpers.d.ts.map +1 -1
  34. package/dist/commands/diff-test-helpers.js +68 -0
  35. package/dist/commands/diff-test-helpers.js.map +1 -1
  36. package/dist/commands/diff-unit-scale-fixtures.d.ts +34 -0
  37. package/dist/commands/diff-unit-scale-fixtures.d.ts.map +1 -0
  38. package/dist/commands/diff-unit-scale-fixtures.js +94 -0
  39. package/dist/commands/diff-unit-scale-fixtures.js.map +1 -0
  40. package/dist/commands/export.d.ts +11 -0
  41. package/dist/commands/export.d.ts.map +1 -1
  42. package/dist/commands/export.js +9 -14
  43. package/dist/commands/export.js.map +1 -1
  44. package/dist/commands/gym.js +2 -2
  45. package/dist/commands/merge.d.ts.map +1 -1
  46. package/dist/commands/merge.js +8 -0
  47. package/dist/commands/merge.js.map +1 -1
  48. package/dist/commands/query-aggregation.d.ts +27 -4
  49. package/dist/commands/query-aggregation.d.ts.map +1 -1
  50. package/dist/commands/query-aggregation.js +67 -6
  51. package/dist/commands/query-aggregation.js.map +1 -1
  52. package/dist/commands/query-output.d.ts +7 -0
  53. package/dist/commands/query-output.d.ts.map +1 -1
  54. package/dist/commands/query-output.js +63 -27
  55. package/dist/commands/query-output.js.map +1 -1
  56. package/dist/commands/query-storey.d.ts +24 -0
  57. package/dist/commands/query-storey.d.ts.map +1 -0
  58. package/dist/commands/query-storey.js +71 -0
  59. package/dist/commands/query-storey.js.map +1 -0
  60. package/dist/commands/query.d.ts +2 -25
  61. package/dist/commands/query.d.ts.map +1 -1
  62. package/dist/commands/query.js +39 -158
  63. package/dist/commands/query.js.map +1 -1
  64. package/dist/commands/schedule-aggregate.d.ts +51 -0
  65. package/dist/commands/schedule-aggregate.d.ts.map +1 -0
  66. package/dist/commands/schedule-aggregate.js +121 -0
  67. package/dist/commands/schedule-aggregate.js.map +1 -0
  68. package/dist/commands/schedule-columns.d.ts +15 -0
  69. package/dist/commands/schedule-columns.d.ts.map +1 -0
  70. package/dist/commands/schedule-columns.js +63 -0
  71. package/dist/commands/schedule-columns.js.map +1 -0
  72. package/dist/commands/schedule-group.d.ts +65 -0
  73. package/dist/commands/schedule-group.d.ts.map +1 -0
  74. package/dist/commands/schedule-group.js +0 -0
  75. package/dist/commands/schedule-group.js.map +1 -0
  76. package/dist/commands/schedule-presets.d.ts +21 -0
  77. package/dist/commands/schedule-presets.d.ts.map +1 -0
  78. package/dist/commands/schedule-presets.js +62 -0
  79. package/dist/commands/schedule-presets.js.map +1 -0
  80. package/dist/commands/schedule-render-html.d.ts +13 -0
  81. package/dist/commands/schedule-render-html.d.ts.map +1 -0
  82. package/dist/commands/schedule-render-html.js +100 -0
  83. package/dist/commands/schedule-render-html.js.map +1 -0
  84. package/dist/commands/schedule-render-md.d.ts +12 -0
  85. package/dist/commands/schedule-render-md.d.ts.map +1 -0
  86. package/dist/commands/schedule-render-md.js +77 -0
  87. package/dist/commands/schedule-render-md.js.map +1 -0
  88. package/dist/commands/schedule-render.d.ts +51 -0
  89. package/dist/commands/schedule-render.d.ts.map +1 -0
  90. package/dist/commands/schedule-render.js +205 -0
  91. package/dist/commands/schedule-render.js.map +1 -0
  92. package/dist/commands/schedule-spec.d.ts +29 -0
  93. package/dist/commands/schedule-spec.d.ts.map +1 -0
  94. package/dist/commands/schedule-spec.js +111 -0
  95. package/dist/commands/schedule-spec.js.map +1 -0
  96. package/dist/commands/schedule.d.ts +23 -0
  97. package/dist/commands/schedule.d.ts.map +1 -0
  98. package/dist/commands/schedule.js +249 -0
  99. package/dist/commands/schedule.js.map +1 -0
  100. package/dist/commands/schema.d.ts.map +1 -1
  101. package/dist/commands/schema.js +192 -17
  102. package/dist/commands/schema.js.map +1 -1
  103. package/dist/commands/stats-aggregation.d.ts +31 -6
  104. package/dist/commands/stats-aggregation.d.ts.map +1 -1
  105. package/dist/commands/stats-aggregation.js +79 -11
  106. package/dist/commands/stats-aggregation.js.map +1 -1
  107. package/dist/commands/stats.d.ts.map +1 -1
  108. package/dist/commands/stats.js +4 -4
  109. package/dist/commands/stats.js.map +1 -1
  110. package/dist/commands/validate.d.ts +7 -4
  111. package/dist/commands/validate.d.ts.map +1 -1
  112. package/dist/commands/validate.js +9 -6
  113. package/dist/commands/validate.js.map +1 -1
  114. package/dist/commands/where-filter.d.ts +42 -0
  115. package/dist/commands/where-filter.d.ts.map +1 -0
  116. package/dist/commands/where-filter.js +88 -0
  117. package/dist/commands/where-filter.js.map +1 -0
  118. package/dist/energy-export.d.ts.map +1 -1
  119. package/dist/energy-export.js +12 -2
  120. package/dist/energy-export.js.map +1 -1
  121. package/dist/geometry-report.d.ts.map +1 -1
  122. package/dist/geometry-report.js +15 -3
  123. package/dist/geometry-report.js.map +1 -1
  124. package/dist/headless-backend.d.ts +20 -5
  125. package/dist/headless-backend.d.ts.map +1 -1
  126. package/dist/headless-backend.js +131 -90
  127. package/dist/headless-backend.js.map +1 -1
  128. package/dist/index.js +28 -0
  129. package/dist/index.js.map +1 -1
  130. package/dist/output.d.ts +13 -0
  131. package/dist/output.d.ts.map +1 -1
  132. package/dist/output.js +21 -0
  133. package/dist/output.js.map +1 -1
  134. package/dist/property-filter-match.d.ts +12 -0
  135. package/dist/property-filter-match.d.ts.map +1 -0
  136. package/dist/property-filter-match.js +17 -0
  137. package/dist/property-filter-match.js.map +1 -0
  138. package/dist/query-overlay-relations.d.ts +29 -0
  139. package/dist/query-overlay-relations.d.ts.map +1 -0
  140. package/dist/query-overlay-relations.js +88 -0
  141. package/dist/query-overlay-relations.js.map +1 -0
  142. package/dist/query-overlay.d.ts +44 -0
  143. package/dist/query-overlay.d.ts.map +1 -0
  144. package/dist/query-overlay.js +100 -0
  145. package/dist/query-overlay.js.map +1 -0
  146. package/package.json +21 -21
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-recipe.d.ts","sourceRoot":"","sources":["../../src/commands/delivery-recipe.ts"],"names":[],"mappings":"AAuCA,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,4EAA4E;AAC5E,MAAM,WAAW,sBAAuB,SAAQ,cAAc;IAC5D,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,4DAA4D;IAC5D,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAQD;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAiEtF"}
@@ -0,0 +1,104 @@
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 saved recipe `ifc-lite delivery` runs.
6
+ *
7
+ * A recipe is a plain JSON file naming one or more model files and the
8
+ * checks to run against every one of them — `structural` (the same rules
9
+ * `ifc-lite validate` runs) and/or one or more `ids` rule files (the same
10
+ * validator `ifc-lite ids` runs). It exists so a delivery check is a single,
11
+ * versioned, reviewable artifact a team commits and re-runs, rather than a
12
+ * remembered shell invocation.
13
+ *
14
+ * ```json
15
+ * {
16
+ * "models": ["model.ifc"],
17
+ * "structural": true,
18
+ * "ids": ["door-rules.ids"]
19
+ * }
20
+ * ```
21
+ *
22
+ * Every `models`/`ids` path is resolved relative to the DIRECTORY CONTAINING
23
+ * THE RECIPE FILE, not the process's current working directory — a recipe
24
+ * committed alongside its fixtures stays runnable from anywhere.
25
+ *
26
+ * A malformed recipe is a `fatal(...)`, matching every other saved-definition
27
+ * loader in this CLI (`schedule-spec.ts`): not valid JSON, not a JSON object,
28
+ * an unrecognised field, a field of the wrong type, an empty/missing
29
+ * `models` list, or declaring NEITHER `structural: true` NOR a non-empty
30
+ * `ids` list (a recipe with zero applicable checks can never produce a
31
+ * meaningful delivery verdict, so it is rejected up front rather than
32
+ * silently reporting an empty "pass").
33
+ */
34
+ import { readFile } from 'node:fs/promises';
35
+ import { dirname, resolve } from 'node:path';
36
+ import { fatal } from '../output.js';
37
+ const RECIPE_FIELDS = ['models', 'structural', 'ids'];
38
+ function isStringArray(value) {
39
+ return Array.isArray(value) && value.every(v => typeof v === 'string');
40
+ }
41
+ /**
42
+ * Load and validate a delivery recipe, resolving every declared path
43
+ * relative to the recipe file's own directory. Every failure mode is a
44
+ * `fatal(...)` with a specific reason — never a silently empty or
45
+ * partially-applied recipe.
46
+ */
47
+ export async function loadDeliveryRecipe(path) {
48
+ let content;
49
+ try {
50
+ content = await readFile(path, 'utf-8');
51
+ }
52
+ catch (err) {
53
+ fatal(`Recipe "${path}" could not be read: ${err.message}`);
54
+ }
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse(content);
58
+ }
59
+ catch (err) {
60
+ fatal(`Recipe "${path}" is not valid JSON: ${err.message}`);
61
+ }
62
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
63
+ fatal(`Recipe "${path}" must be a JSON object with "models" and at least one of "structural"/"ids", got ${Array.isArray(parsed) ? 'an array' : typeof parsed}.`);
64
+ }
65
+ const obj = parsed;
66
+ const unknownKeys = Object.keys(obj).filter(k => !RECIPE_FIELDS.includes(k));
67
+ if (unknownKeys.length > 0) {
68
+ fatal(`Recipe "${path}" has unrecognised field(s): ${unknownKeys.join(', ')}. Valid fields: ${RECIPE_FIELDS.join(', ')}.`);
69
+ }
70
+ if (!('models' in obj) || !isStringArray(obj.models) || obj.models.length === 0) {
71
+ fatal(`Recipe "${path}": "models" must be a non-empty array of file paths.`);
72
+ }
73
+ const models = obj.models;
74
+ if ('structural' in obj && typeof obj.structural !== 'boolean') {
75
+ fatal(`Recipe "${path}": "structural" must be a boolean, got ${typeof obj.structural}.`);
76
+ }
77
+ const structural = obj.structural ?? false;
78
+ if ('ids' in obj && !isStringArray(obj.ids)) {
79
+ fatal(`Recipe "${path}": "ids" must be an array of file paths.`);
80
+ }
81
+ const ids = obj.ids ?? [];
82
+ if (!structural && ids.length === 0) {
83
+ fatal(`Recipe "${path}" declares no applicable checks: set "structural": true and/or a non-empty "ids" list. A zero-check recipe can never produce a delivery verdict.`);
84
+ }
85
+ // Duplicate model/ids entries are rejected rather than silently
86
+ // deduplicated or run twice under one collapsed key: a repeated path is
87
+ // almost certainly a copy-paste mistake in the recipe, and either
88
+ // response (silent dedup, or a doubled report entry) would misrepresent
89
+ // what the recipe actually says it checks.
90
+ const dupModels = models.filter((m, i) => models.indexOf(m) !== i);
91
+ if (dupModels.length > 0) {
92
+ fatal(`Recipe "${path}": "models" lists the same path more than once: ${[...new Set(dupModels)].join(', ')}.`);
93
+ }
94
+ const dupIds = ids.filter((m, i) => ids.indexOf(m) !== i);
95
+ if (dupIds.length > 0) {
96
+ fatal(`Recipe "${path}": "ids" lists the same path more than once: ${[...new Set(dupIds)].join(', ')}.`);
97
+ }
98
+ const recipePath = resolve(path);
99
+ const baseDir = dirname(recipePath);
100
+ const resolvedModels = models.map(m => resolve(baseDir, m));
101
+ const resolvedIds = ids.map(i => resolve(baseDir, i));
102
+ return { recipePath, models, structural, ids, resolvedModels, resolvedIds };
103
+ }
104
+ //# sourceMappingURL=delivery-recipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-recipe.js","sourceRoot":"","sources":["../../src/commands/delivery-recipe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Consolidated report assembly and HTML rendering for `ifc-lite delivery`.
3
+ *
4
+ * Determinism contract: `buildDeliveryReport` never reads the wall clock,
5
+ * never iterates a `Map`/object in insertion-order-dependent ways, and never
6
+ * keys a result by a derived string (model path, IDS file name, check type)
7
+ * — every check is one entry in a flat, declared-order ARRAY. Two collisions
8
+ * this codebase has actually shipped (a subtotal silently overwritten in
9
+ * `schedule`'s output, a duplicate `--columns` header collapsing a row in
10
+ * JSON) both came from keying a result object by a name that two distinct
11
+ * inputs could share; an array keeps every check's own model/type/source
12
+ * fields as data instead of forcing them into a Map/object key that could
13
+ * collide. The result: the SAME recipe run twice, with no model or IDS file
14
+ * changed on disk, produces byte-identical JSON (`tool.version` and the
15
+ * `sha256` fingerprints are the only fields that could ever legitimately
16
+ * differ between two runs, and neither depends on wall-clock time or
17
+ * iteration order).
18
+ */
19
+ import type { StructuralCheckResult, IdsCheckResult } from './delivery-checks.js';
20
+ import type { ResolvedDeliveryRecipe } from './delivery-recipe.js';
21
+ export type DeliveryCheckResult = StructuralCheckResult | IdsCheckResult;
22
+ export interface DeliveryModelEntry {
23
+ /** Path exactly as declared in the recipe (relative, for a readable report). */
24
+ path: string;
25
+ /** SHA-256 of the model's bytes, or undefined when the model could not be loaded. */
26
+ sha256?: string;
27
+ /** Set when the model could not be loaded; every check for this model then reports `error`. */
28
+ loadError?: string;
29
+ }
30
+ export interface DeliveryReport {
31
+ tool: {
32
+ name: 'ifc-lite';
33
+ version: string;
34
+ };
35
+ recipe: string;
36
+ models: DeliveryModelEntry[];
37
+ checks: DeliveryCheckResult[];
38
+ /** `pass` iff every check in `checks` is `pass` and `checks` is non-empty. */
39
+ verdict: 'pass' | 'fail';
40
+ summary: {
41
+ total: number;
42
+ pass: number;
43
+ fail: number;
44
+ error: number;
45
+ };
46
+ }
47
+ /** Build the consolidated report from a resolved recipe, its per-model load outcomes, and every check result. */
48
+ export declare function buildDeliveryReport(recipe: ResolvedDeliveryRecipe, version: string, models: DeliveryModelEntry[], checks: DeliveryCheckResult[]): DeliveryReport;
49
+ /** Render the report as a standalone HTML document — no external assets, safe to open from disk. */
50
+ export declare function renderDeliveryHtml(report: DeliveryReport): string;
51
+ //# sourceMappingURL=delivery-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-report.d.ts","sourceRoot":"","sources":["../../src/commands/delivery-report.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAe,MAAM,sBAAsB,CAAC;AAC/F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,MAAM,mBAAmB,GAAG,qBAAqB,GAAG,cAAc,CAAC;AAEzE,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,8EAA8E;IAC9E,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED,iHAAiH;AACjH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,kBAAkB,EAAE,EAC5B,MAAM,EAAE,mBAAmB,EAAE,GAC5B,cAAc,CAchB;AA+BD,oGAAoG;AACpG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAoEjE"}
@@ -0,0 +1,114 @@
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
+ /** Build the consolidated report from a resolved recipe, its per-model load outcomes, and every check result. */
5
+ export function buildDeliveryReport(recipe, version, models, checks) {
6
+ const counts = { total: checks.length, pass: 0, fail: 0, error: 0 };
7
+ for (const c of checks)
8
+ counts[c.status]++;
9
+ const verdict = checks.length > 0 && counts.fail === 0 && counts.error === 0 ? 'pass' : 'fail';
10
+ return {
11
+ tool: { name: 'ifc-lite', version },
12
+ recipe: recipe.recipePath,
13
+ models,
14
+ checks,
15
+ verdict,
16
+ summary: counts,
17
+ };
18
+ }
19
+ function escapeHtml(value) {
20
+ return value
21
+ .replace(/&/g, '&')
22
+ .replace(/</g, '&lt;')
23
+ .replace(/>/g, '&gt;')
24
+ .replace(/"/g, '&quot;')
25
+ .replace(/'/g, '&#39;');
26
+ }
27
+ function statusBadge(status) {
28
+ const label = status.toUpperCase();
29
+ return `<span class="badge badge-${status}">${label}</span>`;
30
+ }
31
+ function describeCheck(check) {
32
+ if (check.type === 'structural') {
33
+ return `${check.errorCount} error(s), ${check.warningCount} warning(s), ${check.infoCount} info`;
34
+ }
35
+ const parts = [];
36
+ if (check.totalSpecifications !== undefined) {
37
+ parts.push(`${check.passedSpecifications ?? 0}/${check.totalSpecifications} specification(s) passed`);
38
+ }
39
+ if (check.failedEntities !== undefined && check.totalEntities !== undefined) {
40
+ parts.push(`${check.failedEntities}/${check.totalEntities} entities failed`);
41
+ }
42
+ if (check.error)
43
+ parts.push(check.error);
44
+ return parts.join(' — ') || (check.error ?? '');
45
+ }
46
+ /** Render the report as a standalone HTML document — no external assets, safe to open from disk. */
47
+ export function renderDeliveryHtml(report) {
48
+ const rows = report.checks
49
+ .map(check => {
50
+ const source = check.type === 'structural' ? 'structural' : check.source;
51
+ return ` <tr class="row-${check.status}">
52
+ <td>${escapeHtml(check.model)}</td>
53
+ <td>${escapeHtml(check.type)}</td>
54
+ <td>${escapeHtml(source)}</td>
55
+ <td>${statusBadge(check.status)}</td>
56
+ <td>${escapeHtml(describeCheck(check))}</td>
57
+ </tr>`;
58
+ })
59
+ .join('\n');
60
+ const modelRows = report.models
61
+ .map(m => ` <tr>
62
+ <td>${escapeHtml(m.path)}</td>
63
+ <td><code>${escapeHtml(m.sha256 ?? '')}</code></td>
64
+ <td>${m.loadError ? `<span class="badge badge-error">ERROR</span> ${escapeHtml(m.loadError)}` : 'OK'}</td>
65
+ </tr>`)
66
+ .join('\n');
67
+ return `<!doctype html>
68
+ <html lang="en">
69
+ <head>
70
+ <meta charset="utf-8">
71
+ <title>IFC Delivery Check Report</title>
72
+ <style>
73
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; margin: 2rem; color: #1a1a1a; }
74
+ h1 { font-size: 1.4rem; }
75
+ .verdict { font-size: 1.1rem; font-weight: 600; padding: 0.5rem 1rem; border-radius: 4px; display: inline-block; }
76
+ .verdict-pass { background: #e6f4ea; color: #1e7e34; }
77
+ .verdict-fail { background: #fce8e6; color: #c5221f; }
78
+ table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
79
+ th, td { border: 1px solid #ddd; padding: 0.4rem 0.6rem; text-align: left; font-size: 0.9rem; }
80
+ th { background: #f5f5f5; }
81
+ .badge { display: inline-block; padding: 0.1rem 0.5rem; border-radius: 3px; font-size: 0.75rem; font-weight: 600; }
82
+ .badge-pass { background: #e6f4ea; color: #1e7e34; }
83
+ .badge-fail { background: #fce8e6; color: #c5221f; }
84
+ .badge-error { background: #fef7e0; color: #8a6d00; }
85
+ .row-error td { background: #fffdf5; }
86
+ </style>
87
+ </head>
88
+ <body>
89
+ <h1>IFC Delivery Check Report</h1>
90
+ <p><strong>Tool:</strong> ${escapeHtml(report.tool.name)} ${escapeHtml(report.tool.version)}<br>
91
+ <strong>Recipe:</strong> <code>${escapeHtml(report.recipe)}</code></p>
92
+ <p class="verdict verdict-${report.verdict}">Verdict: ${report.verdict.toUpperCase()}</p>
93
+ <p>${report.summary.pass} pass, ${report.summary.fail} fail, ${report.summary.error} error (of ${report.summary.total} check(s))</p>
94
+
95
+ <h2>Models</h2>
96
+ <table>
97
+ <thead><tr><th>Path</th><th>SHA-256</th><th>Status</th></tr></thead>
98
+ <tbody>
99
+ ${modelRows}
100
+ </tbody>
101
+ </table>
102
+
103
+ <h2>Checks</h2>
104
+ <table>
105
+ <thead><tr><th>Model</th><th>Type</th><th>Source</th><th>Status</th><th>Evidence</th></tr></thead>
106
+ <tbody>
107
+ ${rows}
108
+ </tbody>
109
+ </table>
110
+ </body>
111
+ </html>
112
+ `;
113
+ }
114
+ //# sourceMappingURL=delivery-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-report.js","sourceRoot":"","sources":["../../src/commands/delivery-report.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAkD/D,iHAAiH;AACjH,MAAM,UAAU,mBAAmB,CACjC,MAA8B,EAC9B,OAAe,EACf,MAA4B,EAC5B,MAA6B;IAE7B,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACpE,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IAE3C,MAAM,OAAO,GAAoB,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAEhH,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE;QACnC,MAAM,EAAE,MAAM,CAAC,UAAU;QACzB,MAAM;QACN,MAAM;QACN,OAAO;QACP,OAAO,EAAE,MAAM;KAChB,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK;SACT,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,WAAW,CAAC,MAAmB;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,OAAO,4BAA4B,MAAM,KAAK,KAAK,SAAS,CAAC;AAC/D,CAAC;AAED,SAAS,aAAa,CAAC,KAA0B;IAC/C,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAChC,OAAO,GAAG,KAAK,CAAC,UAAU,cAAc,KAAK,CAAC,YAAY,gBAAgB,KAAK,CAAC,SAAS,OAAO,CAAC;IACnG,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,oBAAoB,IAAI,CAAC,IAAI,KAAK,CAAC,mBAAmB,0BAA0B,CAAC,CAAC;IACxG,CAAC;IACD,IAAI,KAAK,CAAC,cAAc,KAAK,SAAS,IAAI,KAAK,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;QAC5E,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,aAAa,kBAAkB,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,KAAK,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,kBAAkB,CAAC,MAAsB;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM;SACvB,GAAG,CAAC,KAAK,CAAC,EAAE;QACX,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;QACzE,OAAO,wBAAwB,KAAK,CAAC,MAAM;cACnC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC;cACvB,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC;cACtB,UAAU,CAAC,MAAM,CAAC;cAClB,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC;cACzB,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;IACT,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM;SAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;cACA,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;oBACZ,UAAU,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;cAChC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gDAAgD,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;YAChG,CAAC;SACR,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;;;;;;;;;;;;;;;;;;;;;;;8BAuBqB,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;sCACvD,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC;8BACjC,MAAM,CAAC,OAAO,cAAc,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE;OAC/E,MAAM,CAAC,OAAO,CAAC,IAAI,UAAU,MAAM,CAAC,OAAO,CAAC,IAAI,UAAU,MAAM,CAAC,OAAO,CAAC,KAAK,cAAc,MAAM,CAAC,OAAO,CAAC,KAAK;;;;;;EAMrH,SAAS;;;;;;;;EAQT,IAAI;;;;;CAKL,CAAC;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function deliveryCommand(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=delivery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../src/commands/delivery.ts"],"names":[],"mappings":"AAyCA,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EnE"}
@@ -0,0 +1,127 @@
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
+ * ifc-lite delivery <recipe.json> [--json] [--out <report.json>] [--html <report.html>]
6
+ *
7
+ * Run a repeatable, reviewable model-delivery check from a saved recipe
8
+ * (see `delivery-recipe.ts`): structural validation (the same rules
9
+ * `ifc-lite validate` runs) and/or IDS validation (the same validator
10
+ * `ifc-lite ids` runs), against one or more model files, in one invocation.
11
+ *
12
+ * Every check reports one of `pass` / `fail` / `error` — never folded
13
+ * together (see `delivery-checks.ts`). The overall verdict is `pass` only
14
+ * when every declared check on every declared model passed; an unreadable
15
+ * model, an unreadable/empty IDS ruleset, or any failed check all produce a
16
+ * `fail` verdict, matching the boundary in issue #3931: "Zero applicable
17
+ * checks or an unreadable model must not be a successful delivery verdict."
18
+ *
19
+ * Output: a human-readable summary to stdout by default, `--json` for the
20
+ * consolidated machine-readable report instead (or `--out <file>` to write
21
+ * that JSON to disk rather than stdout), and `--html <file>` to additionally
22
+ * write a standalone HTML report — the two forms the issue asks for,
23
+ * produced by one invocation.
24
+ *
25
+ * Determinism: given the same recipe and the same bytes on disk, running
26
+ * this command twice produces byte-identical `--json` output (see the
27
+ * contract documented in `delivery-report.ts`).
28
+ */
29
+ import { getFlag, hasFlag, fatal, printJson, writeOutput } from '../output.js';
30
+ import { readCliVersion } from '../version.js';
31
+ import { fileURLToPath } from 'node:url';
32
+ import { dirname, join, relative } from 'node:path';
33
+ import { loadDeliveryRecipe } from './delivery-recipe.js';
34
+ import { loadModelForDelivery, runStructuralCheck, runIdsCheck } from './delivery-checks.js';
35
+ import { buildDeliveryReport, renderDeliveryHtml } from './delivery-report.js';
36
+ const __dirname = dirname(fileURLToPath(import.meta.url));
37
+ const CLI_VERSION = readCliVersion(join(__dirname, '..', '..', 'package.json'));
38
+ export async function deliveryCommand(args) {
39
+ const recipePath = args.find(a => !a.startsWith('-'));
40
+ if (!recipePath) {
41
+ fatal('Usage: ifc-lite delivery <recipe.json> [--json] [--out report.json] [--html report.html]');
42
+ }
43
+ const jsonOutput = hasFlag(args, '--json');
44
+ const outPath = getFlag(args, '--out');
45
+ const htmlPath = getFlag(args, '--html');
46
+ const recipe = await loadDeliveryRecipe(recipePath);
47
+ const models = [];
48
+ const checks = [];
49
+ // Declared order throughout: models in recipe order, and within each
50
+ // model, structural first (when requested) then every --ids file in
51
+ // recipe order. No Map/object iteration anywhere in this loop — see
52
+ // delivery-report.ts's determinism contract.
53
+ for (let i = 0; i < recipe.resolvedModels.length; i++) {
54
+ const declaredPath = recipe.models[i];
55
+ const absPath = recipe.resolvedModels[i];
56
+ const loaded = await loadModelForDelivery(absPath);
57
+ if ('error' in loaded) {
58
+ models.push({ path: declaredPath, loadError: loaded.error });
59
+ // The model could not be loaded: every check the recipe declares for
60
+ // it is unevaluable, and reports `error` — never silently omitted
61
+ // (which would shrink the check count and could flip an
62
+ // otherwise-failing recipe to a false "pass") and never `pass`.
63
+ if (recipe.structural) {
64
+ checks.push({
65
+ type: 'structural', model: declaredPath, status: 'error',
66
+ errorCount: 0, warningCount: 0, infoCount: 0, issues: [],
67
+ error: `model ${loaded.error}`,
68
+ });
69
+ }
70
+ for (const idsDeclared of recipe.ids) {
71
+ checks.push({
72
+ type: 'ids', model: declaredPath, source: idsDeclared, status: 'error',
73
+ error: `model ${loaded.error}`,
74
+ });
75
+ }
76
+ continue;
77
+ }
78
+ models.push({ path: declaredPath, sha256: loaded.sha256 });
79
+ if (recipe.structural) {
80
+ checks.push(runStructuralCheck(declaredPath, loaded.store));
81
+ }
82
+ for (let j = 0; j < recipe.resolvedIds.length; j++) {
83
+ const result = await runIdsCheck(declaredPath, loaded.store, recipe.resolvedIds[j]);
84
+ checks.push({ ...result, source: recipe.ids[j] });
85
+ }
86
+ }
87
+ const report = buildDeliveryReport(recipe, CLI_VERSION, models, checks);
88
+ if (htmlPath) {
89
+ await writeOutput(renderDeliveryHtml(report), htmlPath);
90
+ }
91
+ if (jsonOutput || outPath) {
92
+ if (outPath) {
93
+ await writeOutput(JSON.stringify(report, null, 2), outPath);
94
+ }
95
+ else {
96
+ printJson(report);
97
+ }
98
+ }
99
+ else {
100
+ printHumanSummary(report, recipePath);
101
+ }
102
+ if (report.verdict !== 'pass')
103
+ process.exitCode = 1;
104
+ }
105
+ function printHumanSummary(report, recipePath) {
106
+ process.stdout.write(`\n Delivery check: ${recipePath}\n`);
107
+ process.stdout.write(` ifc-lite ${report.tool.version}\n\n`);
108
+ for (const m of report.models) {
109
+ const rel = relative(process.cwd(), m.path);
110
+ if (m.loadError) {
111
+ process.stdout.write(` [ERR] ${rel}: ${m.loadError}\n`);
112
+ }
113
+ else {
114
+ process.stdout.write(` [OK] ${rel} (sha256 ${m.sha256?.slice(0, 12)}…)\n`);
115
+ }
116
+ }
117
+ process.stdout.write('\n');
118
+ for (const c of report.checks) {
119
+ const icon = c.status === 'pass' ? 'PASS' : c.status === 'fail' ? 'FAIL' : 'ERR ';
120
+ const source = c.type === 'structural' ? 'structural' : c.source;
121
+ const detail = c.error ? ` — ${c.error}` : '';
122
+ process.stdout.write(` [${icon}] ${relative(process.cwd(), c.model)} :: ${source}${detail}\n`);
123
+ }
124
+ process.stdout.write(`\n ${report.summary.pass} pass, ${report.summary.fail} fail, ${report.summary.error} error (of ${report.summary.total})\n`);
125
+ process.stdout.write(` Verdict: ${report.verdict.toUpperCase()}\n\n`);
126
+ }
127
+ //# sourceMappingURL=delivery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../src/commands/delivery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ClassificationInfo } from '@ifc-lite/parser';
2
+ /**
3
+ * Project one resolved classification reference to the single string
4
+ * `DataFingerprintInput.classifications` hashes: `system:identification`,
5
+ * falling back to `name` when the reference carries no identification code.
6
+ * Both blank is "no label" — `''` lets the fingerprint's blank filter drop
7
+ * it, the same rule a blank material name gets. The MCP server's
8
+ * (`packages/mcp/src/tools/diff-fingerprints.ts`) byte-identical twin — must
9
+ * stay one.
10
+ */
11
+ export declare function classificationLabel(info: ClassificationInfo): string;
12
+ //# sourceMappingURL=diff-classification-label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-classification-label.d.ts","sourceRoot":"","sources":["../../src/commands/diff-classification-label.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAKpE"}
@@ -0,0 +1,20 @@
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
+ * Project one resolved classification reference to the single string
6
+ * `DataFingerprintInput.classifications` hashes: `system:identification`,
7
+ * falling back to `name` when the reference carries no identification code.
8
+ * Both blank is "no label" — `''` lets the fingerprint's blank filter drop
9
+ * it, the same rule a blank material name gets. The MCP server's
10
+ * (`packages/mcp/src/tools/diff-fingerprints.ts`) byte-identical twin — must
11
+ * stay one.
12
+ */
13
+ export function classificationLabel(info) {
14
+ const system = info.system?.trim() ?? '';
15
+ const code = (info.identification || info.name || '').trim();
16
+ if (!system && !code)
17
+ return '';
18
+ return `${system}:${code}`;
19
+ }
20
+ //# sourceMappingURL=diff-classification-label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-classification-label.js","sourceRoot":"","sources":["../../src/commands/diff-classification-label.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAI/D;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAwB;IAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACzC,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7D,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"diff-engine.d.ts","sourceRoot":"","sources":["../../src/commands/diff-engine.ts"],"names":[],"mappings":"AA8BA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAML,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAG1B,yEAAyE;AACzE,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,aAAa,CAG9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAavF"}
1
+ {"version":3,"file":"diff-engine.d.ts","sourceRoot":"","sources":["../../src/commands/diff-engine.ts"],"names":[],"mappings":"AA8BA,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAWL,KAAK,YAAY,EAElB,MAAM,kBAAkB,CAAC;AAI1B,yEAAyE;AACzE,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,aAAa,CAG9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAsBvF"}
@@ -28,7 +28,8 @@
28
28
  import { createHash } from 'node:crypto';
29
29
  import { buildComponentFingerprints, buildDataFingerprint, } from '@ifc-lite/diff';
30
30
  import { RelationshipType } from '@ifc-lite/data';
31
- import { EntityExtractor, extractAllEntityAttributes, extractPropertiesOnDemand, extractQuantitiesOnDemand, getAttributeNamesAcrossSchemas, } from '@ifc-lite/parser';
31
+ import { EntityExtractor, extractAllEntityAttributes, extractClassificationsOnDemand, extractProjectUnits, extractPropertiesOnDemand, extractQuantitiesOnDemand, getAttributeNamesAcrossSchemas, quantitySiScale, roundToScale, scaledPropertyValue, } from '@ifc-lite/parser';
32
+ import { classificationLabel } from './diff-classification-label.js';
32
33
  import { comparableEntities } from './diff-scope.js';
33
34
  /**
34
35
  * Content digest of a model's bytes, as written into the sidecar.
@@ -51,9 +52,18 @@ export function modelIdentityOf(path, bytes) {
51
52
  * section of `docs/guide/model-diff.md`).
52
53
  */
53
54
  export function buildFileFingerprints(store) {
55
+ // Resolved once per store, not per entity: the same `IFCUNITASSIGNMENT` walk
56
+ // every property in the file would otherwise repeat, and both `quantitySiScale`
57
+ // and `scaleMeasureValue` are pure over it. An IfcQuantityLength/Area/Volume
58
+ // is stored in the project's raw author unit, exactly like a measure-typed
59
+ // property, so both need the same base-SI conversion before hashing —
60
+ // otherwise a model re-authored in a different project length unit, with no
61
+ // physical quantity actually changed, reports every quantified/measured
62
+ // entity as `modified` (see `buildDataInput`'s scaling comment).
63
+ const units = extractProjectUnits(store.source, store.entityIndex);
54
64
  const fingerprints = [];
55
65
  for (const { expressId, globalId, ifcType, source, isTypeObject } of comparableEntities(store)) {
56
- const input = buildDataInput(store, expressId, ifcType, source, isTypeObject);
66
+ const input = buildDataInput(store, expressId, ifcType, source, isTypeObject, units);
57
67
  fingerprints.push({
58
68
  key: globalId,
59
69
  ifcType,
@@ -78,7 +88,11 @@ function buildDataInput(store, expressId, ifcType,
78
88
  * accessors then answer '' for every display attribute. */
79
89
  source,
80
90
  /** `IfcTypeObject` subtype? Gates `Tag` into the fingerprint (issue #2021). */
81
- isTypeObject) {
91
+ isTypeObject,
92
+ /** The file's declared units, resolved once by {@link buildFileFingerprints},
93
+ * for scaling Qto_ Length/Area/Volume quantities and measure-typed Pset
94
+ * properties to base SI before hashing. */
95
+ units) {
82
96
  const predefinedType = extractAllEntityAttributes(store, expressId).find((attribute) => attribute.name === 'PredefinedType')?.value;
83
97
  // `Tag` for a TYPE OBJECT only. On an occurrence it is the authoring tool's
84
98
  // element id, which changes across producers while the design does not, and
@@ -89,16 +103,21 @@ isTypeObject) {
89
103
  const tag = isTypeObject ? attributeAcrossSchemas(store, expressId, ifcType, 'Tag') : undefined;
90
104
  const propertySets = extractPropertiesOnDemand(store, expressId).map((set) => ({
91
105
  name: set.name,
92
- properties: set.properties.map((property) => ({ name: property.name, value: property.value })),
106
+ properties: set.properties.map((property) => ({
107
+ name: property.name,
108
+ value: scaledPropertyValue(property.value, property.dataType, units),
109
+ })),
93
110
  }));
94
111
  const quantitySets = extractQuantitiesOnDemand(store, expressId).map((set) => ({
95
112
  name: set.name,
96
113
  quantities: set.quantities.map((quantity) => ({
97
114
  name: quantity.name,
98
- // Rounded to 4 dp, matching the viewer: re-exporting a model with
99
- // sub-tolerance float jitter must not flip the data hash on an otherwise
100
- // identical element, which on this path would cost the pair its match.
101
- value: roundQuantity(quantity.value),
115
+ // Scaled to base SI first (a Qto_ value is stored in the project's raw
116
+ // author unit, see `quantitySiScale`), then rounded to 4 dp, matching
117
+ // the viewer: re-exporting a model with sub-tolerance float jitter must
118
+ // not flip the data hash on an otherwise identical element, which on
119
+ // this path would cost the pair its match.
120
+ value: roundToScale(quantity.value * quantitySiScale(quantity, units)),
102
121
  })),
103
122
  }));
104
123
  const typeAssignments = store.relationships
@@ -108,6 +127,11 @@ isTypeObject) {
108
127
  name: store.entities.getName(typeId) || undefined,
109
128
  type: store.entities.getTypeName(typeId) || undefined,
110
129
  }));
130
+ // Resolved classification references (never entity references — see
131
+ // `DataFingerprintInput.classifications`): an `IfcRelAssociatesClassification`
132
+ // has no channel of its own here, so a re-coded element — geometry and every
133
+ // property untouched — previously read as unchanged on every path.
134
+ const classifications = extractClassificationsOnDemand(store, expressId).map(classificationLabel);
111
135
  return {
112
136
  ifcType,
113
137
  name: store.entities.getName(expressId) || source?.name || undefined,
@@ -118,11 +142,9 @@ isTypeObject) {
118
142
  propertySets,
119
143
  quantitySets,
120
144
  typeAssignments,
145
+ classifications,
121
146
  };
122
147
  }
123
- function roundQuantity(value) {
124
- return Number.isFinite(value) ? Math.round(value * 1e4) / 1e4 : value;
125
- }
126
148
  /**
127
149
  * One named attribute, read positionally through the **cross-schema** attribute
128
150
  * list (issue #2021).
@@ -1 +1 @@
1
- {"version":3,"file":"diff-engine.js","sourceRoot":"","sources":["../../src/commands/diff-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diff-engine.js","sourceRoot":"","sources":["../../src/commands/diff-engine.ts"],"names":[],"mappings":"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"}
@@ -94,4 +94,16 @@ export declare function infraRevisionModel(revision: 1 | 2): string;
94
94
  export declare const BASE_MODEL: string;
95
95
  /** Same building, re-exported: the two walls carry brand-new GlobalIds. */
96
96
  export declare const HEAD_MODEL: string;
97
+ /** A minimal model with one wall carrying one `Qto_` length quantity, under a
98
+ * chosen project length unit and a chosen raw quantity value — for the
99
+ * unit-of-measure oracle case (a Qto_ value is stored in the project's raw
100
+ * author unit, not base SI; see `quantitySiScale`). */
101
+ export declare function quantityModel(lengthUnit: 'METRE' | 'MILLIMETRE', qtyValue: number, explicitQuantityUnit?: 'METRE' | 'MILLIMETRE'): string;
102
+ /**
103
+ * A minimal model with one wall associated to one Uniclass-style
104
+ * classification reference, under a chosen identification code — for the
105
+ * classification oracle case (an `IfcRelAssociatesClassification` re-coding
106
+ * with no geometry, property or quantity edit).
107
+ */
108
+ export declare function classificationModel(identification: string): string;
97
109
  //# sourceMappingURL=diff-test-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"diff-test-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/diff-test-helpers.ts"],"names":[],"mappings":"AAIA,kFAAkF;AAElF,yDAAyD;AACzD,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;wDAEwD;AACxD,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA4B1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+BtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA0B5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAwBrC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAmBtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CA+B1D;AAED,eAAO,MAAM,UAAU,QAAoC,CAAC;AAC5D,2EAA2E;AAC3E,eAAO,MAAM,UAAU,QAAoC,CAAC"}
1
+ {"version":3,"file":"diff-test-helpers.d.ts","sourceRoot":"","sources":["../../src/commands/diff-test-helpers.ts"],"names":[],"mappings":"AAIA,kFAAkF;AAElF,yDAAyD;AACzD,wBAAgB,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;wDAEwD;AACxD,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CA4B1D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+BtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA0B5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAwBrC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAmBtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CA+B1D;AAED,eAAO,MAAM,UAAU,QAAoC,CAAC;AAC5D,2EAA2E;AAC3E,eAAO,MAAM,UAAU,QAAoC,CAAC;AAE5D;;;wDAGwD;AACxD,wBAAgB,aAAa,CAC3B,UAAU,EAAE,OAAO,GAAG,YAAY,EAClC,QAAQ,EAAE,MAAM,EAChB,oBAAoB,CAAC,EAAE,OAAO,GAAG,YAAY,GAC5C,MAAM,CAiCR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAwBlE"}