@things-factory/figure-ui 10.1.147 → 10.1.149

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 (209) hide show
  1. package/client/bootstrap.ts +10 -2
  2. package/client/graphql/index.ts +20 -0
  3. package/client/modeller/canvas.ts +6 -2
  4. package/client/modeller/carrier-declaration.ts +63 -0
  5. package/client/modeller/editor.ts +62 -27
  6. package/client/modeller/figure-carrier.ts +117 -0
  7. package/client/modeller/figure-cavity-drawing.ts +3 -9
  8. package/client/modeller/figure-first-save.ts +4 -7
  9. package/client/modeller/figure-history-panel.ts +2 -3
  10. package/client/modeller/figure-links.ts +46 -60
  11. package/client/modeller/figure-material-panel.ts +4 -14
  12. package/client/modeller/figure-mesh-choice.ts +68 -0
  13. package/client/modeller/figure-parts.ts +23 -1
  14. package/client/modeller/figure-preview.ts +2 -2
  15. package/client/modeller/figure-properties.ts +5 -3
  16. package/client/modeller/figure-section-editor.ts +12 -33
  17. package/client/modeller/figure-section-panel.ts +6 -7
  18. package/client/modeller/figure-slot-layout-panel.ts +208 -0
  19. package/client/modeller/figure-verdict.ts +21 -31
  20. package/client/modeller/first-save.ts +23 -0
  21. package/client/modeller/links.ts +52 -1
  22. package/client/modeller/material-edit.ts +38 -0
  23. package/client/modeller/maturity.ts +28 -0
  24. package/client/modeller/mesh-import.ts +77 -0
  25. package/client/modeller/modeller-route.ts +9 -0
  26. package/client/modeller/mounting-part.ts +15 -0
  27. package/client/modeller/newest-answer.ts +21 -0
  28. package/client/modeller/preview-model.ts +5 -0
  29. package/client/modeller/refusals.ts +168 -82
  30. package/client/modeller/section-controls.ts +25 -1
  31. package/client/modeller/section-drawing.ts +43 -1
  32. package/client/modeller/slot-layout-host.ts +140 -0
  33. package/client/pages/figure-modeller-page.ts +6 -5
  34. package/client/viewparts/detail-route.ts +7 -0
  35. package/client/viewparts/figure-detail-dock.ts +1 -3
  36. package/dist-client/bootstrap.d.ts +1 -1
  37. package/dist-client/bootstrap.js +9 -2
  38. package/dist-client/bootstrap.js.map +1 -1
  39. package/dist-client/graphql/index.d.ts +5 -0
  40. package/dist-client/graphql/index.js +19 -0
  41. package/dist-client/graphql/index.js.map +1 -1
  42. package/dist-client/modeller/canvas.d.ts +2 -0
  43. package/dist-client/modeller/canvas.js +10 -2
  44. package/dist-client/modeller/canvas.js.map +1 -1
  45. package/dist-client/modeller/carrier-declaration.d.ts +31 -0
  46. package/dist-client/modeller/carrier-declaration.js +53 -0
  47. package/dist-client/modeller/carrier-declaration.js.map +1 -0
  48. package/dist-client/modeller/editor.d.ts +13 -0
  49. package/dist-client/modeller/editor.js +62 -27
  50. package/dist-client/modeller/editor.js.map +1 -1
  51. package/dist-client/modeller/figure-carrier.d.ts +26 -0
  52. package/dist-client/modeller/figure-carrier.js +123 -0
  53. package/dist-client/modeller/figure-carrier.js.map +1 -0
  54. package/dist-client/modeller/figure-cavity-drawing.js +3 -11
  55. package/dist-client/modeller/figure-cavity-drawing.js.map +1 -1
  56. package/dist-client/modeller/figure-first-save.d.ts +4 -0
  57. package/dist-client/modeller/figure-first-save.js +5 -8
  58. package/dist-client/modeller/figure-first-save.js.map +1 -1
  59. package/dist-client/modeller/figure-history-panel.js +2 -4
  60. package/dist-client/modeller/figure-history-panel.js.map +1 -1
  61. package/dist-client/modeller/figure-links.d.ts +4 -1
  62. package/dist-client/modeller/figure-links.js +47 -57
  63. package/dist-client/modeller/figure-links.js.map +1 -1
  64. package/dist-client/modeller/figure-material-panel.d.ts +0 -1
  65. package/dist-client/modeller/figure-material-panel.js +4 -14
  66. package/dist-client/modeller/figure-material-panel.js.map +1 -1
  67. package/dist-client/modeller/figure-mesh-choice.d.ts +16 -0
  68. package/dist-client/modeller/figure-mesh-choice.js +75 -0
  69. package/dist-client/modeller/figure-mesh-choice.js.map +1 -0
  70. package/dist-client/modeller/figure-parts.d.ts +1 -1
  71. package/dist-client/modeller/figure-parts.js +22 -0
  72. package/dist-client/modeller/figure-parts.js.map +1 -1
  73. package/dist-client/modeller/figure-preview.js +2 -2
  74. package/dist-client/modeller/figure-preview.js.map +1 -1
  75. package/dist-client/modeller/figure-properties.d.ts +2 -1
  76. package/dist-client/modeller/figure-properties.js +5 -3
  77. package/dist-client/modeller/figure-properties.js.map +1 -1
  78. package/dist-client/modeller/figure-section-editor.d.ts +2 -2
  79. package/dist-client/modeller/figure-section-editor.js +12 -33
  80. package/dist-client/modeller/figure-section-editor.js.map +1 -1
  81. package/dist-client/modeller/figure-section-panel.js +6 -7
  82. package/dist-client/modeller/figure-section-panel.js.map +1 -1
  83. package/dist-client/modeller/figure-slot-layout-panel.d.ts +36 -0
  84. package/dist-client/modeller/figure-slot-layout-panel.js +198 -0
  85. package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -0
  86. package/dist-client/modeller/figure-verdict.d.ts +1 -1
  87. package/dist-client/modeller/figure-verdict.js +19 -37
  88. package/dist-client/modeller/figure-verdict.js.map +1 -1
  89. package/dist-client/modeller/first-save.d.ts +10 -0
  90. package/dist-client/modeller/first-save.js +16 -0
  91. package/dist-client/modeller/first-save.js.map +1 -1
  92. package/dist-client/modeller/links.d.ts +26 -1
  93. package/dist-client/modeller/links.js +43 -0
  94. package/dist-client/modeller/links.js.map +1 -1
  95. package/dist-client/modeller/material-edit.d.ts +11 -0
  96. package/dist-client/modeller/material-edit.js +28 -0
  97. package/dist-client/modeller/material-edit.js.map +1 -0
  98. package/dist-client/modeller/maturity.d.ts +15 -0
  99. package/dist-client/modeller/maturity.js +23 -0
  100. package/dist-client/modeller/maturity.js.map +1 -1
  101. package/dist-client/modeller/mesh-import.d.ts +47 -0
  102. package/dist-client/modeller/mesh-import.js +47 -0
  103. package/dist-client/modeller/mesh-import.js.map +1 -0
  104. package/dist-client/modeller/modeller-route.d.ts +5 -0
  105. package/dist-client/modeller/modeller-route.js +9 -0
  106. package/dist-client/modeller/modeller-route.js.map +1 -1
  107. package/dist-client/modeller/mounting-part.d.ts +14 -0
  108. package/dist-client/modeller/mounting-part.js +10 -0
  109. package/dist-client/modeller/mounting-part.js.map +1 -0
  110. package/dist-client/modeller/newest-answer.d.ts +12 -0
  111. package/dist-client/modeller/newest-answer.js +21 -0
  112. package/dist-client/modeller/newest-answer.js.map +1 -0
  113. package/dist-client/modeller/preview-model.d.ts +2 -0
  114. package/dist-client/modeller/preview-model.js +4 -0
  115. package/dist-client/modeller/preview-model.js.map +1 -1
  116. package/dist-client/modeller/refusals.d.ts +26 -5
  117. package/dist-client/modeller/refusals.js +184 -86
  118. package/dist-client/modeller/refusals.js.map +1 -1
  119. package/dist-client/modeller/section-controls.d.ts +17 -1
  120. package/dist-client/modeller/section-controls.js +18 -0
  121. package/dist-client/modeller/section-controls.js.map +1 -1
  122. package/dist-client/modeller/section-drawing.d.ts +24 -1
  123. package/dist-client/modeller/section-drawing.js +42 -0
  124. package/dist-client/modeller/section-drawing.js.map +1 -1
  125. package/dist-client/modeller/slot-layout-host.d.ts +81 -0
  126. package/dist-client/modeller/slot-layout-host.js +105 -0
  127. package/dist-client/modeller/slot-layout-host.js.map +1 -0
  128. package/dist-client/pages/figure-modeller-page.js +5 -4
  129. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  130. package/dist-client/tsconfig.tsbuildinfo +1 -1
  131. package/dist-client/viewparts/detail-route.d.ts +5 -0
  132. package/dist-client/viewparts/detail-route.js +8 -0
  133. package/dist-client/viewparts/detail-route.js.map +1 -0
  134. package/dist-client/viewparts/figure-detail-dock.d.ts +0 -1
  135. package/dist-client/viewparts/figure-detail-dock.js +1 -3
  136. package/dist-client/viewparts/figure-detail-dock.js.map +1 -1
  137. package/package.json +9 -8
  138. package/test/align.test.ts +0 -9
  139. package/test/browser/assistant-stand-in.js +32 -0
  140. package/test/browser/build.mjs +6 -1
  141. package/test/browser/editing-page.js +224 -0
  142. package/test/browser/editing.check.mjs +550 -0
  143. package/test/browser/links-page.js +113 -0
  144. package/test/browser/links.check.mjs +568 -0
  145. package/test/browser/modeller.check.mjs +21 -0
  146. package/test/browser/parts-page.js +120 -0
  147. package/test/browser/parts.check.mjs +328 -0
  148. package/test/browser/places-mesh-page.js +36 -0
  149. package/test/browser/places-mesh.check.mjs +239 -0
  150. package/test/browser/product-page.check.mjs +682 -0
  151. package/test/browser/product-page.js +276 -0
  152. package/test/browser/screen-page.js +112 -0
  153. package/test/browser/screen-product-page.js +62 -0
  154. package/test/browser/screen.check.mjs +1003 -0
  155. package/test/browser/section-page.js +256 -0
  156. package/test/browser/section.check.mjs +719 -0
  157. package/test/browser/serve.mjs +20 -12
  158. package/test/carrier-declaration.test.ts +69 -0
  159. package/test/cavity-drawing.test.ts +2 -18
  160. package/test/clip-ai-proposal.test.ts +1 -5
  161. package/test/clip-consent.test.ts +0 -5
  162. package/test/clips.test.ts +0 -7
  163. package/test/command-preview.test.ts +0 -68
  164. package/test/controls.test.ts +0 -9
  165. package/test/detail-dock.test.ts +6 -25
  166. package/test/face-mapping.test.ts +1 -20
  167. package/test/fasten-drawing.test.ts +0 -23
  168. package/test/fields.test.ts +6 -33
  169. package/test/figure-assistant-surface.test.ts +32 -38
  170. package/test/first-minute.test.ts +3 -55
  171. package/test/first-save-suggest.test.ts +11 -8
  172. package/test/first-save.test.ts +4 -26
  173. package/test/gizmo.test.ts +0 -25
  174. package/test/joint-fan.test.ts +0 -10
  175. package/test/keys.test.ts +0 -7
  176. package/test/layout.test.ts +4 -73
  177. package/test/links.test.ts +48 -67
  178. package/test/live.test.ts +0 -34
  179. package/test/material.test.ts +17 -26
  180. package/test/maturity.test.ts +13 -16
  181. package/test/mesh-import.test.ts +76 -0
  182. package/test/modeller-route.test.ts +3 -19
  183. package/test/package-download.test.ts +6 -7
  184. package/test/parts-wiring.test.ts +9 -51
  185. package/test/preview.test.ts +5 -46
  186. package/test/properties.test.ts +11 -26
  187. package/test/proposal-record.test.ts +2 -19
  188. package/test/recipes.test.ts +0 -15
  189. package/test/refusals.test.ts +257 -151
  190. package/test/release-entry.test.ts +1 -9
  191. package/test/release-panel.test.ts +1 -22
  192. package/test/resize-with-placement.test.ts +0 -32
  193. package/test/revert-choice.test.ts +1 -22
  194. package/test/revert-keeping.test.ts +1 -12
  195. package/test/save-landed.test.ts +16 -14
  196. package/test/scene-canvas.test.ts +2 -13
  197. package/test/section-editor.test.ts +30 -83
  198. package/test/section-panel.test.ts +22 -17
  199. package/test/slot-layout-host.test.ts +117 -0
  200. package/test/theme.test.ts +5 -9
  201. package/test/verdict.test.ts +44 -41
  202. package/test/view.test.ts +5 -12
  203. package/translations/en.json +61 -1
  204. package/translations/es.json +61 -1
  205. package/translations/ja.json +61 -1
  206. package/translations/ko.json +61 -1
  207. package/translations/ms.json +61 -1
  208. package/translations/zh.json +61 -1
  209. package/test/thumbnail.test.ts +0 -29
@@ -1,31 +1,39 @@
1
1
  /*
2
- * A command refused because the figure could not be drawn at an end of its declared size range, in the author's words
3
- * with the numbers and where to put it right -- not the kernel's English (user, 2026-09-24: 「what is this warning
4
- * message means?」). Kept apart from the element so it is tested without a browser.
2
+ * A command figure-model refused, in the author's words with the numbers and where to put it right -- not the kernel's
3
+ * English (user, 2026-09-24: 「what is this warning message means?」). Kept apart from the element so it is tested
4
+ * without a browser.
5
+ *
6
+ * Every sentence here is made from the refusal's `code` and `details` (ADR-0127), never from its message: the kernel's
7
+ * English is for logs and readers of the kernel, and a screen that read it went quiet whenever a sentence changed or a
8
+ * new one came under the same code (ADR-0054). A refusal with no details the screen knows is said with its code.
5
9
  */
6
- /** The refusal in words, or nothing for any other refusal. */
10
+ import { FIGURE_INSTANCE_SIZE_INPUTS } from '@hatiolab/figure-model';
11
+ const codeOf = (error) => error?.code;
12
+ /** The refusal's details when they are of this reason, or nothing. */
13
+ function detailsOf(error, reason) {
14
+ const details = error?.details;
15
+ return details?.reason === reason ? details : undefined;
16
+ }
17
+ const mmOf = (mm) => mm.toLocaleString(undefined, { maximumFractionDigits: 1 });
18
+ const numberOf = (value) => value.toLocaleString(undefined, { maximumFractionDigits: 3 });
19
+ /** Bytes in KiB, rounded up: a figure a few bytes over its limit is not said to be at it. */
20
+ const kibOf = (bytes) => Math.ceil(bytes / 1024).toLocaleString();
21
+ /** A size range the figure cannot be drawn over, or one that leaves out its own size, in words; nothing for any other refusal. */
7
22
  export function sizeRangeRefusalOf(error, say) {
8
- if (error?.code !== 'INSTANCE_SIZE_RANGE')
23
+ if (codeOf(error) !== 'INSTANCE_SIZE_RANGE')
9
24
  return null;
10
- const message = error instanceof Error ? error.message : String(error);
11
- const mmOf = (raw) => Number(raw).toLocaleString(undefined, { maximumFractionDigits: 1 });
12
- const found = /size\.([xyz]):\s*(below|above) ([\d.]+) mm [^(;]*(?:\(([^)]+)\))?;/.exec(message);
13
- if (found) {
14
- const [, axis, side, mm, part] = found;
15
- return say(side === 'below' ? 'figure.text.size-range-too-small' : 'figure.text.size-range-too-large', { axis: axis.toUpperCase(), mm: mmOf(mm), part: part ?? '' });
16
- }
17
- /* The kernel's other sentences under this code: a range that leaves out the size the figure is drawn at, a smallest size of zero, a part already gone at that size. */
18
- const outside = /size\.([xyz]):\s*the authored size ([\d.]+) mm must lie within ([\d.]+)…([\d.]+) mm/.exec(message);
19
- if (outside) {
20
- const [, axis, at, min, max] = outside;
21
- return say('figure.text.size-range-leaves-out-size', { axis: axis.toUpperCase(), at: mmOf(at), min: mmOf(min), max: mmOf(max) });
22
- }
23
- const zero = /size\.([xyz]):\s*the smallest size must be above zero/.exec(message);
25
+ const reach = detailsOf(error, 'size-cannot-reach');
26
+ if (reach)
27
+ return say(reach.bound === 'min' ? 'figure.text.size-range-too-small' : 'figure.text.size-range-too-large', { axis: reach.axis.toUpperCase(), mm: mmOf(reach.need), part: reach.part ?? '' });
28
+ const outside = detailsOf(error, 'size-outside-range');
29
+ if (outside)
30
+ return say('figure.text.size-range-leaves-out-size', { axis: outside.axis.toUpperCase(), at: mmOf(outside.at), min: mmOf(outside.min), max: mmOf(outside.max) });
31
+ const zero = detailsOf(error, 'size-min-not-positive');
24
32
  if (zero)
25
- return say('figure.text.size-range-from-zero', { axis: zero[1].toUpperCase() });
26
- const gone = /size\.([xyz]):\s*the figure is authored at ([\d.]+) mm, where a length is already gone/.exec(message);
33
+ return say('figure.text.size-range-from-zero', { axis: zero.axis.toUpperCase() });
34
+ const gone = detailsOf(error, 'size-already-gone');
27
35
  if (gone)
28
- return say('figure.text.size-range-part-gone', { axis: gone[1].toUpperCase(), at: mmOf(gone[2]) });
36
+ return say('figure.text.size-range-part-gone', { axis: gone.axis.toUpperCase(), at: mmOf(gone.at) });
29
37
  return null;
30
38
  }
31
39
  /**
@@ -33,18 +41,16 @@ export function sizeRangeRefusalOf(error, say) {
33
41
  * to measure), so the author is offered the same link that narrows the range to what the figure then allows.
34
42
  */
35
43
  export function narrowingRetryOf(action, error, say) {
36
- if (action.kind !== 'link-dimension' || error?.code !== 'INSTANCE_SIZE_RANGE')
44
+ if (action.kind !== 'link-dimension' || codeOf(error) !== 'INSTANCE_SIZE_RANGE')
37
45
  return null;
38
- const message = error instanceof Error ? error.message : String(error);
39
- const found = /size\.([xyz]):\s*(below|above) ([\d.]+) mm [^(;]*(?:\(([^)]+)\))?;/.exec(message);
40
- if (!found)
46
+ const reach = detailsOf(error, 'size-cannot-reach');
47
+ if (!reach)
41
48
  return null;
42
- const [, axis, side, raw, part] = found;
43
- const mm = Number(raw).toLocaleString(undefined, { maximumFractionDigits: 1 });
44
- const words = { axis: axis.toUpperCase(), mm, part: part ?? '' };
49
+ const words = { axis: reach.axis.toUpperCase(), mm: mmOf(reach.need), part: reach.part ?? '' };
50
+ const below = reach.bound === 'min';
45
51
  return {
46
- message: say(side === 'below' ? 'figure.text.link-needs-smaller-range' : 'figure.text.link-needs-larger-range', words),
47
- label: say(side === 'below' ? 'figure.button.narrow-range-from' : 'figure.button.narrow-range-to', words),
52
+ message: say(below ? 'figure.text.link-needs-smaller-range' : 'figure.text.link-needs-larger-range', words),
53
+ label: say(below ? 'figure.button.narrow-range-from' : 'figure.button.narrow-range-to', words),
48
54
  retry: { ...action, narrowRange: true }
49
55
  };
50
56
  }
@@ -53,17 +59,20 @@ export function narrowingRetryOf(action, error, say) {
53
59
  * on the floor, when the figure is to hang on a wall), said in the author's words with the parts it names.
54
60
  */
55
61
  export function placementRefusalOf(error, say) {
56
- if (error?.code !== 'PLACEMENT_PLANE')
62
+ if (codeOf(error) !== 'PLACEMENT_PLANE')
57
63
  return null;
58
- const message = error instanceof Error ? error.message : String(error);
59
- const found = /: (.+?) (?:is|are) fastened to the mounting plane by a face an? (\w+) does not take \(([^)]+)\)/.exec(message);
60
- if (!found)
64
+ const misfit = detailsOf(error, 'placement-face');
65
+ if (!misfit)
61
66
  return null;
62
- return say('figure.text.placement-plane-refused', { parts: found[1], placement: say('figure.label.placement-' + found[2], {}), faces: found[3] });
67
+ return say('figure.text.placement-plane-refused', {
68
+ parts: misfit.parts.map(p => `${p.part} (${p.face})`).join(', '),
69
+ placement: say('figure.label.placement-' + misfit.placement, {}),
70
+ faces: misfit.takes.join(', ')
71
+ });
63
72
  }
64
73
  /** A part refused because the declared room reads it -- the one refusal deleting it with the room refitted answers. */
65
74
  export function inDeclaredRoom(error) {
66
- return error?.code === 'PART_REFERENCED' && /is in the space the figure declares/.test(error instanceof Error ? error.message : String(error));
75
+ return codeOf(error) === 'PART_REFERENCED' && !!detailsOf(error, 'in-declared-space');
67
76
  }
68
77
  /**
69
78
  * Why a part cannot be deleted, in the author's words. Since the chief architect's ruling of 2026-09-27 a part that
@@ -71,26 +80,48 @@ export function inDeclaredRoom(error) {
71
80
  * left is the declared space (with a way on: fit it again) and a row -- one laid along the part, or hanging in its row.
72
81
  */
73
82
  export function partRefusalOf(error, part, say) {
74
- const code = error?.code;
83
+ const code = codeOf(error);
75
84
  if (code !== 'PART_REFERENCED' && code !== 'PART_ROW')
76
85
  return null;
77
- /* figure-model's sentence after its code and path: 「PART_ROW: bed: roller is a row laid along bed; …」. */
78
- const message = (error instanceof Error ? error.message : String(error)).replace(/^[A-Z_]+: [^:]+: /, '');
79
- if (/is in the space the figure declares/.test(message))
86
+ if (detailsOf(error, 'in-declared-space'))
80
87
  return say('figure.text.part-in-declared-space', { part });
81
- const along = /^(.+?) (?:is a row|are rows) laid along /.exec(message);
88
+ const along = detailsOf(error, 'row-along');
82
89
  if (along)
83
- return say('figure.text.part-row-along', { part, rows: along[1] });
84
- const carried = /^(.+?) hangs? in the row /.exec(message);
90
+ return say('figure.text.part-row-along', { part, rows: along.rows.join(', ') });
91
+ const carried = detailsOf(error, 'hangs-in-row');
85
92
  if (carried)
86
- return say('figure.text.part-row-carries', { part, others: carried[1] });
93
+ return say('figure.text.part-row-carries', { part, others: carried.parts.join(', ') });
87
94
  return say('figure.text.part-is-referenced', { part });
88
95
  }
96
+ /** A part the gizmo cannot move because a joint or a fastening places it, named as the author knows it (`part`). */
97
+ export function placedRefusalOf(error, part, say) {
98
+ if (codeOf(error) !== 'EDIT_TARGET')
99
+ return null;
100
+ if (detailsOf(error, 'placed-by-joint'))
101
+ return say('figure.text.gizmo-joint-places', { part });
102
+ if (detailsOf(error, 'placed-by-fastening'))
103
+ return say('figure.text.gizmo-fastening-places', { part });
104
+ return null;
105
+ }
106
+ /** A part name refused: not a name, already used, or another part is named under the part. The rule is the kernel's. */
107
+ export function partNameRefusalOf(error, say) {
108
+ if (codeOf(error) !== 'PART_ID')
109
+ return null;
110
+ const invalid = detailsOf(error, 'name-invalid');
111
+ if (invalid)
112
+ return say('figure.text.part-name-invalid', { name: invalid.name });
113
+ const taken = detailsOf(error, 'name-taken');
114
+ if (taken)
115
+ return say('figure.text.part-name-taken', { name: taken.name });
116
+ const nested = detailsOf(error, 'name-has-nested');
117
+ if (nested)
118
+ return say('figure.text.part-name-has-nested', { nested: nested.nested });
119
+ return null;
120
+ }
89
121
  /** What removing a part let go of (figure-model's `RemovalNotice`), said in one line, or nothing when it let go of nothing. */
90
122
  export function removalNoticeOf(notice, say) {
91
123
  if (!notice)
92
124
  return null;
93
- const number = (v) => v.toLocaleString(undefined, { maximumFractionDigits: 3 });
94
125
  const lines = [];
95
126
  const still = notice.released.filter(r => !r.control).map(r => r.part);
96
127
  if (still.length)
@@ -98,7 +129,7 @@ export function removalNoticeOf(notice, say) {
98
129
  for (const r of notice.released.filter(r => r.control))
99
130
  lines.push(say('figure.text.removal-released-motion', { part: r.part, control: r.control }));
100
131
  for (const c of notice.controls)
101
- lines.push(say('figure.text.removal-own-control', { part: c.part, control: c.control, min: number(c.min), max: number(c.max) }));
132
+ lines.push(say('figure.text.removal-own-control', { part: c.part, control: c.control, min: numberOf(c.min), max: numberOf(c.max) }));
102
133
  const fixed = [...new Set(notice.fixed.map(f => f.part))];
103
134
  if (fixed.length)
104
135
  lines.push(say('figure.text.removal-fixed', { parts: fixed.join(', ') }));
@@ -110,70 +141,137 @@ export function removalNoticeOf(notice, say) {
110
141
  }
111
142
  /**
112
143
  * A recipe refused at one of its steps: which step, and why -- the particular sentence when there is one (a size
113
- * range, a value's range, a placement), otherwise the kernel's code. The kernel says 「steps[2]: attach: …」.
144
+ * range, a value's range, a placement), otherwise the kernel's code. The step is the refusal's path, `steps[2]`: the
145
+ * contract's path grammar, not its English (ADR-0127 decision 6).
114
146
  */
115
147
  export function recipeRefusalOf(error, say) {
116
148
  const step = /^steps\[(\d+)\]$/.exec(error?.path ?? '');
117
149
  if (!step)
118
150
  return null;
119
151
  const why = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ?? placementRefusalOf(error, say);
120
- return say('figure.text.recipe-step-refused', { step: String(Number(step[1]) + 1), why: why ?? '', code: error?.code ?? '' });
152
+ return say('figure.text.recipe-step-refused', { step: String(Number(step[1]) + 1), why: why ?? '', code: codeOf(error) ?? '' });
121
153
  }
122
- /**
123
- * A refusal no sentence above knows, said as a refusal with its code -- never the kernel's English on the screen (the
124
- * duplicate of a row's part showed 「EDIT_TARGET: … not a repeated template」, 2026-09-27). The figure's node limit
125
- * is said with its number.
126
- */
127
154
  /**
128
155
  * A corner or an inside the part cannot take (ADR-0100 stage 1): what was too large or too thick, or what holds on
129
- * to what the edit would take away. The kernel names the problem in its message; the screen names it in words.
156
+ * to what the edit would take away.
130
157
  */
131
- function sectionRefusalOf(code, message, say) {
132
- if (code === 'FEATURE_MAPPING_REQUIRED') {
133
- /* 「takes away inside-bottom (joint j1); top (feature f2)」: the faces, each in the author's words. */
134
- const faces = [...message.matchAll(/([\w-]+) \([^)]*\)/g)].map(([, face]) => say('figure.label.face-' + face, {}));
135
- return say('figure.text.section-face-in-use', { faces: faces.join(', ') });
136
- }
137
- if (code === 'DIMENSION_LINKED')
158
+ function sectionRefusalOf(error, say) {
159
+ const mapping = detailsOf(error, 'faces-taken-away');
160
+ if (mapping)
161
+ return say('figure.text.section-face-in-use', { faces: mapping.lost.map(l => say('figure.label.face-' + l.face, {})).join(', ') });
162
+ if (codeOf(error) === 'DIMENSION_LINKED')
138
163
  return say('figure.text.section-dimension-linked', {});
139
- if (code !== 'GEOMETRY_DOMAIN')
140
- return null;
141
- if (/CORNER_TOO_LARGE/.test(message))
164
+ if (detailsOf(error, 'section-invalid')?.issues.some(i => i.code === 'CORNER_TOO_LARGE'))
142
165
  return say('figure.text.section-corner-too-large', {});
143
- if (/NO_ROOM_INSIDE/.test(message))
166
+ const inside = detailsOf(error, 'inside-invalid')?.refusal;
167
+ if (inside?.code === 'CAVITY' && inside.refused === 'NO_ROOM_INSIDE')
144
168
  return say('figure.text.section-wall-too-thick', {});
145
- if (/CAVITY_NO_LENGTH/.test(message))
169
+ if (inside?.code === 'CAVITY_NO_LENGTH')
146
170
  return say('figure.text.section-ends-too-thick', {});
147
171
  return null;
148
172
  }
173
+ /**
174
+ * A slot layout refused (ADR-0118): the anchor, slot or value it was refused for. The layout's own findings are named
175
+ * by where they are; the editor checks them before Apply, so they rarely reach here.
176
+ */
177
+ export function slotLayoutRefusalOf(error, say) {
178
+ if (detailsOf(error, 'slot-layout-label-missing'))
179
+ return say('figure.text.slot-layout-label-missing', {});
180
+ if (detailsOf(error, 'slot-anchors-missing'))
181
+ return say('figure.text.slot-anchors-missing', {});
182
+ const twice = detailsOf(error, 'slot-anchor-duplicate');
183
+ if (twice)
184
+ return say('figure.text.slot-anchor-duplicate', { anchor: twice.anchor });
185
+ const flat = detailsOf(error, 'slot-anchor-not-flat');
186
+ if (flat)
187
+ return say('figure.text.slot-anchor-not-flat', { anchor: flat.anchor, part: flat.part });
188
+ const gone = detailsOf(error, 'slot-anchor-no-part');
189
+ if (gone)
190
+ return say('figure.text.slot-anchor-no-part', { anchor: gone.anchor, part: gone.part });
191
+ const issues = detailsOf(error, 'slot-layout-issues');
192
+ if (issues)
193
+ return say('figure.text.slot-layout-issues', { path: issues.issues[0]?.path ?? '' });
194
+ const empty = detailsOf(error, 'slot-accepts-empty');
195
+ if (empty)
196
+ return say('figure.text.slot-accepts-empty', { slot: empty.slot });
197
+ const taken = detailsOf(error, 'slot-id-taken');
198
+ if (taken)
199
+ return say('figure.text.slot-id-taken', { slot: taken.slot });
200
+ return null;
201
+ }
202
+ /** The figure's limits: its nodes, its size saved, how deep it nests. */
203
+ function documentLimitRefusalOf(error, say) {
204
+ if (codeOf(error) !== 'DOCUMENT_LIMIT')
205
+ return null;
206
+ const nodes = detailsOf(error, 'node-limit');
207
+ if (nodes)
208
+ return say('figure.text.edit-refused-node-limit', { max: String(nodes.max) });
209
+ const large = detailsOf(error, 'document-too-large');
210
+ if (large)
211
+ return large.at === undefined
212
+ ? say('figure.text.document-too-large-unmeasured', { max: kibOf(large.max) })
213
+ : say('figure.text.document-too-large', { max: kibOf(large.max), at: kibOf(large.at) });
214
+ const deep = detailsOf(error, 'nesting-too-deep');
215
+ if (deep)
216
+ return say('figure.text.document-nesting-too-deep', { max: String(deep.max), at: String(deep.at) });
217
+ return null;
218
+ }
219
+ /**
220
+ * A refusal in the author's words when the screen has words for it, otherwise said as a refusal with its code -- never
221
+ * the kernel's English on the screen (the duplicate of a row's part showed 「EDIT_TARGET: … not a repeated template」,
222
+ * 2026-09-27).
223
+ */
149
224
  export function editRefusalOf(error, say) {
150
- const code = error?.code;
151
- const message = error instanceof Error ? error.message : String(error);
152
- if (code === 'DOCUMENT_LIMIT')
153
- return say('figure.text.edit-refused-node-limit', { max: /maximum (\d+) nodes/.exec(message)?.[1] ?? '' });
154
- const section = sectionRefusalOf(code, message, say);
155
- if (section)
156
- return section;
157
- return say('figure.text.edit-refused', { code: code ?? '' });
225
+ return (sizeRangeRefusalOf(error, say) ??
226
+ inputRangeRefusalOf(error, say) ??
227
+ repeatPitchRefusalOf(error, say) ??
228
+ rowLimitRefusalOf(error, say) ??
229
+ placementRefusalOf(error, say) ??
230
+ partNameRefusalOf(error, say) ??
231
+ documentLimitRefusalOf(error, say) ??
232
+ sectionRefusalOf(error, say) ??
233
+ slotLayoutRefusalOf(error, say) ??
234
+ say('figure.text.edit-refused', { code: codeOf(error) ?? '' }));
158
235
  }
159
236
  /**
160
- * A value outside the range its input declares, with the range and the value given -- the kernel says
161
- * 「size.x: 6021100 outside [300,1200]」. The figure's own size is named by its axis; any other input by its range only.
162
- * The repeat pitch's refusal shares the code and has its own words (`figure.text.repeat-pitch-too-small`).
237
+ * A value outside the range its input declares, with the range and the value given. The figure's own size is named by
238
+ * its axis; any other input by its range only.
163
239
  */
164
240
  export function inputRangeRefusalOf(error, say) {
165
- if (error?.code !== 'INPUT_RANGE')
241
+ if (codeOf(error) !== 'INPUT_RANGE')
166
242
  return null;
167
- const message = error instanceof Error ? error.message : String(error);
168
- const found = /([\w.-]+): (-?[\d.e+]+) outside \[(-?[\d.e+]+),\s*(-?[\d.e+]+)\]/.exec(message);
169
- if (!found)
243
+ const range = detailsOf(error, 'value-outside-range');
244
+ if (!range)
170
245
  return null;
171
- const [, input, value, min, max] = found;
172
- const number = (text) => Number(text).toLocaleString(undefined, { maximumFractionDigits: 3 });
173
- const axis = /^size\.([xyz])$/.exec(input)?.[1];
174
- const params = { value: number(value), min: number(min), max: number(max) };
246
+ const axis = Object.entries(FIGURE_INSTANCE_SIZE_INPUTS).find(([, id]) => id === range.input)?.[0];
247
+ const params = { value: numberOf(range.value), min: numberOf(range.min), max: numberOf(range.max) };
175
248
  return axis ? say('figure.text.input-range-size', { ...params, axis: axis.toUpperCase() }) : say('figure.text.input-range', params);
176
249
  }
250
+ /**
251
+ * A row past its limits: a pitch so fine it would hold more copies than a row takes, a row that would expand to more
252
+ * bodies than a figure draws, or a number of copies outside what a row may have.
253
+ */
254
+ export function rowLimitRefusalOf(error, say) {
255
+ const copies = detailsOf(error, 'copies-over-limit');
256
+ if (copies)
257
+ return say('figure.text.row-copies-over-limit', { count: copies.count.toLocaleString(), limit: copies.limit.toLocaleString() });
258
+ const bodies = detailsOf(error, 'geometry-over-limit');
259
+ if (bodies)
260
+ return say('figure.text.row-geometry-over-limit', { count: bodies.count.toLocaleString(), limit: bodies.limit.toLocaleString() });
261
+ const count = detailsOf(error, 'row-copies-out-of-range');
262
+ if (count)
263
+ return say('figure.text.row-copies-out-of-range', { count: count.count.toLocaleString(), min: String(count.min), max: String(count.max) });
264
+ return null;
265
+ }
266
+ /** A row's pitch under which the figure, at the length it is authored, would hold more copies than a row takes. */
267
+ export function repeatPitchRefusalOf(error, say) {
268
+ if (codeOf(error) !== 'INPUT_RANGE')
269
+ return null;
270
+ const pitch = detailsOf(error, 'pitch-too-many-copies');
271
+ if (!pitch)
272
+ return null;
273
+ return say('figure.text.repeat-pitch-too-small', { length: pitch.length.toLocaleString(), min: String(pitch.least), limit: String(pitch.limit) });
274
+ }
177
275
  /**
178
276
  * Why "follow the size and keep where the figure is placed" was not applied, in the author's words (ADR-0097): the plan
179
277
  * says what it would have had to overwrite, and for a part through the plane how far. A code the screen has no words
@@ -1 +1 @@
1
- {"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../client/modeller/refusals.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,8DAA8D;AAC9D,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAAE,GAAQ;IACzD,IAAK,KAA2B,EAAE,IAAI,KAAK,qBAAqB;QAAE,OAAO,IAAI,CAAA;IAC7E,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAA;IACjG,MAAM,KAAK,GAAG,oEAAoE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAChG,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,KAAK,CAAA;QACtC,OAAO,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC,CAAC,CAAC,kCAAkC,EAAE,EAAE,IAAI,EAAE,IAAK,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAG,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAA;IACxK,CAAC;IACD,uKAAuK;IACvK,MAAM,OAAO,GAAG,qFAAqF,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnH,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,OAAO,CAAA;QACtC,OAAO,GAAG,CAAC,wCAAwC,EAAE,EAAE,IAAI,EAAE,IAAK,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAG,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAI,CAAC,EAAE,CAAC,CAAA;IACtI,CAAC;IACD,MAAM,IAAI,GAAG,uDAAuD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAClF,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC,kCAAkC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IAC1F,MAAM,IAAI,GAAG,wFAAwF,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACnH,IAAI,IAAI;QAAE,OAAO,GAAG,CAAC,kCAAkC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAA;IAC9G,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAA6B,MAAS,EAAE,KAAc,EAAE,GAAQ;IAC9F,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,IAAK,KAA2B,EAAE,IAAI,KAAK,qBAAqB;QAAE,OAAO,IAAI,CAAA;IACjH,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,MAAM,KAAK,GAAG,oEAAoE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAChG,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,KAAK,CAAA;IACvC,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAA;IAC9E,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,IAAK,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAA;IACjE,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,qCAAqC,EAAE,KAAK,CAAC;QACtH,KAAK,EAAE,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,+BAA+B,EAAE,KAAK,CAAC;QACzG,KAAK,EAAE,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE;KACxC,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc,EAAE,GAAQ;IACzD,IAAK,KAA2B,EAAE,IAAI,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAA;IACzE,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,MAAM,KAAK,GAAG,iGAAiG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC7H,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,GAAG,CAAC,qCAAqC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,SAAS,EAAE,GAAG,CAAC,yBAAyB,GAAG,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,CAAC,CAAA;AACtJ,CAAC;AAED,uHAAuH;AACvH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAQ,KAA2B,EAAE,IAAI,KAAK,iBAAiB,IAAI,qCAAqC,CAAC,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;AACvK,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,IAAY,EAAE,GAAQ;IAClE,MAAM,IAAI,GAAI,KAA2B,EAAE,IAAI,CAAA;IAC/C,IAAI,IAAI,KAAK,iBAAiB,IAAI,IAAI,KAAK,UAAU;QAAE,OAAO,IAAI,CAAA;IAClE,0GAA0G;IAC1G,MAAM,OAAO,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;IACzG,IAAI,qCAAqC,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,oCAAoC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;IACnH,MAAM,KAAK,GAAG,0CAA0C,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACtE,IAAI,KAAK;QAAE,OAAO,GAAG,CAAC,4BAA4B,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,CAAC,CAAA;IAC9E,MAAM,OAAO,GAAG,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACzD,IAAI,OAAO;QAAE,OAAO,GAAG,CAAC,8BAA8B,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAE,EAAE,CAAC,CAAA;IACtF,OAAO,GAAG,CAAC,gCAAgC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;AACxD,CAAC;AAED,+HAA+H;AAC/H,MAAM,UAAU,eAAe,CAC7B,MAQa,EACb,GAAQ;IAER,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IACxB,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAA;IACvF,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;IACtE,IAAI,KAAK,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9F,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,qCAAqC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAQ,EAAE,CAAC,CAAC,CAAA;IACrJ,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,iCAAiC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IACjK,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACzD,IAAI,KAAK,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IAC3F,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,8BAA8B,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9I,IAAI,MAAM,CAAC,YAAY;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,mCAAmC,EAAE,EAAE,CAAC,CAAC,CAAA;IACjF,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,GAAQ;IACtD,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAE,KAA2B,EAAE,IAAI,IAAI,EAAE,CAAC,CAAA;IAC9E,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACtB,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,mBAAmB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,kBAAkB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAC/G,OAAO,GAAG,CAAC,iCAAiC,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,EAAG,KAA2B,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAA;AACtJ,CAAC;AAED;;;;GAIG;AACH;;;GAGG;AACH,SAAS,gBAAgB,CAAC,IAAwB,EAAE,OAAe,EAAE,GAAQ;IAC3E,IAAI,IAAI,KAAK,0BAA0B,EAAE,CAAC;QACxC,qGAAqG;QACrG,MAAM,KAAK,GAAG,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,oBAAoB,GAAG,IAAI,EAAE,EAAE,CAAC,CAAC,CAAA;QAClH,OAAO,GAAG,CAAC,iCAAiC,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC5E,CAAC;IACD,IAAI,IAAI,KAAK,kBAAkB;QAAE,OAAO,GAAG,CAAC,sCAAsC,EAAE,EAAE,CAAC,CAAA;IACvF,IAAI,IAAI,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAA;IAC3C,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,sCAAsC,EAAE,EAAE,CAAC,CAAA;IAC5F,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,oCAAoC,EAAE,EAAE,CAAC,CAAA;IACxF,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC,oCAAoC,EAAE,EAAE,CAAC,CAAA;IAC1F,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,GAAQ;IACpD,MAAM,IAAI,GAAI,KAA2B,EAAE,IAAI,CAAA;IAC/C,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,IAAI,IAAI,KAAK,gBAAgB;QAAE,OAAO,GAAG,CAAC,qCAAqC,EAAE,EAAE,GAAG,EAAE,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACzI,MAAM,OAAO,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;IACpD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAA;IAC3B,OAAO,GAAG,CAAC,0BAA0B,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAA;AAC9D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAc,EAAE,GAAQ;IAC1D,IAAK,KAA2B,EAAE,IAAI,KAAK,aAAa;QAAE,OAAO,IAAI,CAAA;IACrE,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACtE,MAAM,KAAK,GAAG,kEAAkE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC9F,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,CAAA;IACxC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAA;IACrG,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAChD,MAAM,MAAM,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAI,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAI,CAAC,EAAE,CAAA;IAC9E,OAAO,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,8BAA8B,EAAE,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAA;AACrI,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAA8E,EAAE,IAAY,EAAE,GAAQ;IACpI,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAA;IAC5B,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,CAAA;IACvB,MAAM,KAAK,GAAG,GAAG,CAAC,6BAA6B,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IAC/D,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;IAC5I,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,YAAY,EAAE,SAAS,CAAC,CAAA;IAC5H,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,8BAA8B,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IACnI,OAAO,GAAG,CAAC,0BAA0B,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAA;AAChE,CAAC","sourcesContent":["/*\n * A command refused because the figure could not be drawn at an end of its declared size range, in the author's words\n * with the numbers and where to put it right -- not the kernel's English (user, 2026-09-24: 「what is this warning\n * message means?」). Kept apart from the element so it is tested without a browser.\n */\n\ntype Say = (key: string, params: Record<string, string>) => string\n\n/** The refusal in words, or nothing for any other refusal. */\nexport function sizeRangeRefusalOf(error: unknown, say: Say): string | null {\n if ((error as { code?: string })?.code !== 'INSTANCE_SIZE_RANGE') return null\n const message = error instanceof Error ? error.message : String(error)\n const mmOf = (raw: string) => Number(raw).toLocaleString(undefined, { maximumFractionDigits: 1 })\n const found = /size\\.([xyz]):\\s*(below|above) ([\\d.]+) mm [^(;]*(?:\\(([^)]+)\\))?;/.exec(message)\n if (found) {\n const [, axis, side, mm, part] = found\n return say(side === 'below' ? 'figure.text.size-range-too-small' : 'figure.text.size-range-too-large', { axis: axis!.toUpperCase(), mm: mmOf(mm!), part: part ?? '' })\n }\n /* The kernel's other sentences under this code: a range that leaves out the size the figure is drawn at, a smallest size of zero, a part already gone at that size. */\n const outside = /size\\.([xyz]):\\s*the authored size ([\\d.]+) mm must lie within ([\\d.]+)…([\\d.]+) mm/.exec(message)\n if (outside) {\n const [, axis, at, min, max] = outside\n return say('figure.text.size-range-leaves-out-size', { axis: axis!.toUpperCase(), at: mmOf(at!), min: mmOf(min!), max: mmOf(max!) })\n }\n const zero = /size\\.([xyz]):\\s*the smallest size must be above zero/.exec(message)\n if (zero) return say('figure.text.size-range-from-zero', { axis: zero[1]!.toUpperCase() })\n const gone = /size\\.([xyz]):\\s*the figure is authored at ([\\d.]+) mm, where a length is already gone/.exec(message)\n if (gone) return say('figure.text.size-range-part-gone', { axis: gone[1]!.toUpperCase(), at: mmOf(gone[2]!) })\n return null\n}\n\n/**\n * A link refused because the size range it would leave cannot hold: measuring again cannot help (the link is not there\n * to measure), so the author is offered the same link that narrows the range to what the figure then allows.\n */\nexport function narrowingRetryOf<A extends { kind: string }>(action: A, error: unknown, say: Say): { message: string; label: string; retry: A & { narrowRange: true } } | null {\n if (action.kind !== 'link-dimension' || (error as { code?: string })?.code !== 'INSTANCE_SIZE_RANGE') return null\n const message = error instanceof Error ? error.message : String(error)\n const found = /size\\.([xyz]):\\s*(below|above) ([\\d.]+) mm [^(;]*(?:\\(([^)]+)\\))?;/.exec(message)\n if (!found) return null\n const [, axis, side, raw, part] = found\n const mm = Number(raw).toLocaleString(undefined, { maximumFractionDigits: 1 })\n const words = { axis: axis!.toUpperCase(), mm, part: part ?? '' }\n return {\n message: say(side === 'below' ? 'figure.text.link-needs-smaller-range' : 'figure.text.link-needs-larger-range', words),\n label: say(side === 'below' ? 'figure.button.narrow-range-from' : 'figure.button.narrow-range-to', words),\n retry: { ...action, narrowRange: true }\n }\n}\n\n/**\n * A placement refused because a part is fastened to the mounting plane by a face the new plane does not take (a bottom\n * on the floor, when the figure is to hang on a wall), said in the author's words with the parts it names.\n */\nexport function placementRefusalOf(error: unknown, say: Say): string | null {\n if ((error as { code?: string })?.code !== 'PLACEMENT_PLANE') return null\n const message = error instanceof Error ? error.message : String(error)\n const found = /: (.+?) (?:is|are) fastened to the mounting plane by a face an? (\\w+) does not take \\(([^)]+)\\)/.exec(message)\n if (!found) return null\n return say('figure.text.placement-plane-refused', { parts: found[1]!, placement: say('figure.label.placement-' + found[2]!, {}), faces: found[3]! })\n}\n\n/** A part refused because the declared room reads it -- the one refusal deleting it with the room refitted answers. */\nexport function inDeclaredRoom(error: unknown): boolean {\n return (error as { code?: string })?.code === 'PART_REFERENCED' && /is in the space the figure declares/.test(error instanceof Error ? error.message : String(error))\n}\n\n/**\n * Why a part cannot be deleted, in the author's words. Since the chief architect's ruling of 2026-09-27 a part that\n * holds others, leads a motion or is followed goes, and what depended on it is let go of (`removalNoticeOf`); what is\n * left is the declared space (with a way on: fit it again) and a row -- one laid along the part, or hanging in its row.\n */\nexport function partRefusalOf(error: unknown, part: string, say: Say): string | null {\n const code = (error as { code?: string })?.code\n if (code !== 'PART_REFERENCED' && code !== 'PART_ROW') return null\n /* figure-model's sentence after its code and path: 「PART_ROW: bed: roller is a row laid along bed; …」. */\n const message = (error instanceof Error ? error.message : String(error)).replace(/^[A-Z_]+: [^:]+: /, '')\n if (/is in the space the figure declares/.test(message)) return say('figure.text.part-in-declared-space', { part })\n const along = /^(.+?) (?:is a row|are rows) laid along /.exec(message)\n if (along) return say('figure.text.part-row-along', { part, rows: along[1]! })\n const carried = /^(.+?) hangs? in the row /.exec(message)\n if (carried) return say('figure.text.part-row-carries', { part, others: carried[1]! })\n return say('figure.text.part-is-referenced', { part })\n}\n\n/** What removing a part let go of (figure-model's `RemovalNotice`), said in one line, or nothing when it let go of nothing. */\nexport function removalNoticeOf(\n notice:\n | {\n released: Array<{ part: string; control?: string }>\n fixed: Array<{ part: string }>\n controls: Array<{ part: string; control: string; min: number; max: number }>\n mountingFace?: boolean\n bindings?: Array<{ id: string; label?: string }>\n }\n | undefined,\n say: Say\n): string | null {\n if (!notice) return null\n const number = (v: number) => v.toLocaleString(undefined, { maximumFractionDigits: 3 })\n const lines: string[] = []\n const still = notice.released.filter(r => !r.control).map(r => r.part)\n if (still.length) lines.push(say('figure.text.removal-released', { parts: still.join(', ') }))\n for (const r of notice.released.filter(r => r.control)) lines.push(say('figure.text.removal-released-motion', { part: r.part, control: r.control! }))\n for (const c of notice.controls) lines.push(say('figure.text.removal-own-control', { part: c.part, control: c.control, min: number(c.min), max: number(c.max) }))\n const fixed = [...new Set(notice.fixed.map(f => f.part))]\n if (fixed.length) lines.push(say('figure.text.removal-fixed', { parts: fixed.join(', ') }))\n if (notice.bindings?.length) lines.push(say('figure.text.removal-bindings', { places: notice.bindings.map(b => b.label ?? b.id).join(', ') }))\n if (notice.mountingFace) lines.push(say('figure.text.removal-mounting-face', {}))\n return lines.length ? lines.join(' ') : null\n}\n\n/**\n * A recipe refused at one of its steps: which step, and why -- the particular sentence when there is one (a size\n * range, a value's range, a placement), otherwise the kernel's code. The kernel says 「steps[2]: attach: …」.\n */\nexport function recipeRefusalOf(error: unknown, say: Say): string | null {\n const step = /^steps\\[(\\d+)\\]$/.exec((error as { path?: string })?.path ?? '')\n if (!step) return null\n const why = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ?? placementRefusalOf(error, say)\n return say('figure.text.recipe-step-refused', { step: String(Number(step[1]) + 1), why: why ?? '', code: (error as { code?: string })?.code ?? '' })\n}\n\n/**\n * A refusal no sentence above knows, said as a refusal with its code -- never the kernel's English on the screen (the\n * duplicate of a row's part showed 「EDIT_TARGET: … not a repeated template」, 2026-09-27). The figure's node limit\n * is said with its number.\n */\n/**\n * A corner or an inside the part cannot take (ADR-0100 stage 1): what was too large or too thick, or what holds on\n * to what the edit would take away. The kernel names the problem in its message; the screen names it in words.\n */\nfunction sectionRefusalOf(code: string | undefined, message: string, say: Say): string | null {\n if (code === 'FEATURE_MAPPING_REQUIRED') {\n /* 「takes away inside-bottom (joint j1); top (feature f2)」: the faces, each in the author's words. */\n const faces = [...message.matchAll(/([\\w-]+) \\([^)]*\\)/g)].map(([, face]) => say('figure.label.face-' + face, {}))\n return say('figure.text.section-face-in-use', { faces: faces.join(', ') })\n }\n if (code === 'DIMENSION_LINKED') return say('figure.text.section-dimension-linked', {})\n if (code !== 'GEOMETRY_DOMAIN') return null\n if (/CORNER_TOO_LARGE/.test(message)) return say('figure.text.section-corner-too-large', {})\n if (/NO_ROOM_INSIDE/.test(message)) return say('figure.text.section-wall-too-thick', {})\n if (/CAVITY_NO_LENGTH/.test(message)) return say('figure.text.section-ends-too-thick', {})\n return null\n}\n\nexport function editRefusalOf(error: unknown, say: Say): string {\n const code = (error as { code?: string })?.code\n const message = error instanceof Error ? error.message : String(error)\n if (code === 'DOCUMENT_LIMIT') return say('figure.text.edit-refused-node-limit', { max: /maximum (\\d+) nodes/.exec(message)?.[1] ?? '' })\n const section = sectionRefusalOf(code, message, say)\n if (section) return section\n return say('figure.text.edit-refused', { code: code ?? '' })\n}\n\n/**\n * A value outside the range its input declares, with the range and the value given -- the kernel says\n * 「size.x: 6021100 outside [300,1200]」. The figure's own size is named by its axis; any other input by its range only.\n * The repeat pitch's refusal shares the code and has its own words (`figure.text.repeat-pitch-too-small`).\n */\nexport function inputRangeRefusalOf(error: unknown, say: Say): string | null {\n if ((error as { code?: string })?.code !== 'INPUT_RANGE') return null\n const message = error instanceof Error ? error.message : String(error)\n const found = /([\\w.-]+): (-?[\\d.e+]+) outside \\[(-?[\\d.e+]+),\\s*(-?[\\d.e+]+)\\]/.exec(message)\n if (!found) return null\n const [, input, value, min, max] = found\n const number = (text: string) => Number(text).toLocaleString(undefined, { maximumFractionDigits: 3 })\n const axis = /^size\\.([xyz])$/.exec(input!)?.[1]\n const params = { value: number(value!), min: number(min!), max: number(max!) }\n return axis ? say('figure.text.input-range-size', { ...params, axis: axis.toUpperCase() }) : say('figure.text.input-range', params)\n}\n\n/**\n * Why \"follow the size and keep where the figure is placed\" was not applied, in the author's words (ADR-0097): the plan\n * says what it would have had to overwrite, and for a part through the plane how far. A code the screen has no words\n * for is said as a refusal with its code, never in the kernel's English.\n */\nexport function resizeRefusalOf(plan: { mode: string; refusal?: { code: string; axis?: string; mm?: number } }, part: string, say: Say): string {\n const refusal = plan.refusal\n if (!refusal) return ''\n const place = say(`figure.label.resize-place-${plan.mode}`, {})\n const params = { part, place, axis: (refusal.axis ?? '').toUpperCase(), mm: refusal.mm === undefined ? '' : String(Math.round(refusal.mm)) }\n const known = ['HELD', 'TURNED', 'UNIFORM_POLICY', 'SHAPE_EDIT', 'DIMENSION_RULE', 'POSITION_RULE', 'GAP_CHOICE', 'NO_FACE']\n if (known.includes(refusal.code)) return say(`figure.text.resize-refused-${refusal.code.toLowerCase().replace(/_/g, '-')}`, params)\n return say('figure.text.edit-refused', { code: refusal.code })\n}\n"]}
1
+ {"version":3,"file":"refusals.js","sourceRoot":"","sources":["../../client/modeller/refusals.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * A command figure-model refused, in the author's words with the numbers and where to put it right -- not the kernel's\n * English (user, 2026-09-24: 「what is this warning message means?」). Kept apart from the element so it is tested\n * without a browser.\n *\n * Every sentence here is made from the refusal's `code` and `details` (ADR-0127), never from its message: the kernel's\n * English is for logs and readers of the kernel, and a screen that read it went quiet whenever a sentence changed or a\n * new one came under the same code (ADR-0054). A refusal with no details the screen knows is said with its code.\n */\nimport { FIGURE_INSTANCE_SIZE_INPUTS, type FigureRefusalDetails } from '@hatiolab/figure-model'\n\ntype Say = (key: string, params: Record<string, string>) => string\ntype Reason = FigureRefusalDetails['reason']\n\nconst codeOf = (error: unknown) => (error as { code?: string } | null | undefined)?.code\n/** The refusal's details when they are of this reason, or nothing. */\nfunction detailsOf<R extends Reason>(error: unknown, reason: R): Extract<FigureRefusalDetails, { reason: R }> | undefined {\n const details = (error as { details?: FigureRefusalDetails } | null | undefined)?.details\n return details?.reason === reason ? (details as Extract<FigureRefusalDetails, { reason: R }>) : undefined\n}\nconst mmOf = (mm: number) => mm.toLocaleString(undefined, { maximumFractionDigits: 1 })\nconst numberOf = (value: number) => value.toLocaleString(undefined, { maximumFractionDigits: 3 })\n/** Bytes in KiB, rounded up: a figure a few bytes over its limit is not said to be at it. */\nconst kibOf = (bytes: number) => Math.ceil(bytes / 1024).toLocaleString()\n\n/** A size range the figure cannot be drawn over, or one that leaves out its own size, in words; nothing for any other refusal. */\nexport function sizeRangeRefusalOf(error: unknown, say: Say): string | null {\n if (codeOf(error) !== 'INSTANCE_SIZE_RANGE') return null\n const reach = detailsOf(error, 'size-cannot-reach')\n if (reach)\n return say(reach.bound === 'min' ? 'figure.text.size-range-too-small' : 'figure.text.size-range-too-large', { axis: reach.axis.toUpperCase(), mm: mmOf(reach.need), part: reach.part ?? '' })\n const outside = detailsOf(error, 'size-outside-range')\n if (outside) return say('figure.text.size-range-leaves-out-size', { axis: outside.axis.toUpperCase(), at: mmOf(outside.at), min: mmOf(outside.min), max: mmOf(outside.max) })\n const zero = detailsOf(error, 'size-min-not-positive')\n if (zero) return say('figure.text.size-range-from-zero', { axis: zero.axis.toUpperCase() })\n const gone = detailsOf(error, 'size-already-gone')\n if (gone) return say('figure.text.size-range-part-gone', { axis: gone.axis.toUpperCase(), at: mmOf(gone.at) })\n return null\n}\n\n/**\n * A link refused because the size range it would leave cannot hold: measuring again cannot help (the link is not there\n * to measure), so the author is offered the same link that narrows the range to what the figure then allows.\n */\nexport function narrowingRetryOf<A extends { kind: string }>(action: A, error: unknown, say: Say): { message: string; label: string; retry: A & { narrowRange: true } } | null {\n if (action.kind !== 'link-dimension' || codeOf(error) !== 'INSTANCE_SIZE_RANGE') return null\n const reach = detailsOf(error, 'size-cannot-reach')\n if (!reach) return null\n const words = { axis: reach.axis.toUpperCase(), mm: mmOf(reach.need), part: reach.part ?? '' }\n const below = reach.bound === 'min'\n return {\n message: say(below ? 'figure.text.link-needs-smaller-range' : 'figure.text.link-needs-larger-range', words),\n label: say(below ? 'figure.button.narrow-range-from' : 'figure.button.narrow-range-to', words),\n retry: { ...action, narrowRange: true }\n }\n}\n\n/**\n * A placement refused because a part is fastened to the mounting plane by a face the new plane does not take (a bottom\n * on the floor, when the figure is to hang on a wall), said in the author's words with the parts it names.\n */\nexport function placementRefusalOf(error: unknown, say: Say): string | null {\n if (codeOf(error) !== 'PLACEMENT_PLANE') return null\n const misfit = detailsOf(error, 'placement-face')\n if (!misfit) return null\n return say('figure.text.placement-plane-refused', {\n parts: misfit.parts.map(p => `${p.part} (${p.face})`).join(', '),\n placement: say('figure.label.placement-' + misfit.placement, {}),\n faces: misfit.takes.join(', ')\n })\n}\n\n/** A part refused because the declared room reads it -- the one refusal deleting it with the room refitted answers. */\nexport function inDeclaredRoom(error: unknown): boolean {\n return codeOf(error) === 'PART_REFERENCED' && !!detailsOf(error, 'in-declared-space')\n}\n\n/**\n * Why a part cannot be deleted, in the author's words. Since the chief architect's ruling of 2026-09-27 a part that\n * holds others, leads a motion or is followed goes, and what depended on it is let go of (`removalNoticeOf`); what is\n * left is the declared space (with a way on: fit it again) and a row -- one laid along the part, or hanging in its row.\n */\nexport function partRefusalOf(error: unknown, part: string, say: Say): string | null {\n const code = codeOf(error)\n if (code !== 'PART_REFERENCED' && code !== 'PART_ROW') return null\n if (detailsOf(error, 'in-declared-space')) return say('figure.text.part-in-declared-space', { part })\n const along = detailsOf(error, 'row-along')\n if (along) return say('figure.text.part-row-along', { part, rows: along.rows.join(', ') })\n const carried = detailsOf(error, 'hangs-in-row')\n if (carried) return say('figure.text.part-row-carries', { part, others: carried.parts.join(', ') })\n return say('figure.text.part-is-referenced', { part })\n}\n\n/** A part the gizmo cannot move because a joint or a fastening places it, named as the author knows it (`part`). */\nexport function placedRefusalOf(error: unknown, part: string, say: Say): string | null {\n if (codeOf(error) !== 'EDIT_TARGET') return null\n if (detailsOf(error, 'placed-by-joint')) return say('figure.text.gizmo-joint-places', { part })\n if (detailsOf(error, 'placed-by-fastening')) return say('figure.text.gizmo-fastening-places', { part })\n return null\n}\n\n/** A part name refused: not a name, already used, or another part is named under the part. The rule is the kernel's. */\nexport function partNameRefusalOf(error: unknown, say: Say): string | null {\n if (codeOf(error) !== 'PART_ID') return null\n const invalid = detailsOf(error, 'name-invalid')\n if (invalid) return say('figure.text.part-name-invalid', { name: invalid.name })\n const taken = detailsOf(error, 'name-taken')\n if (taken) return say('figure.text.part-name-taken', { name: taken.name })\n const nested = detailsOf(error, 'name-has-nested')\n if (nested) return say('figure.text.part-name-has-nested', { nested: nested.nested })\n return null\n}\n\n/** What removing a part let go of (figure-model's `RemovalNotice`), said in one line, or nothing when it let go of nothing. */\nexport function removalNoticeOf(\n notice:\n | {\n released: Array<{ part: string; control?: string }>\n fixed: Array<{ part: string }>\n controls: Array<{ part: string; control: string; min: number; max: number }>\n mountingFace?: boolean\n bindings?: Array<{ id: string; label?: string }>\n }\n | undefined,\n say: Say\n): string | null {\n if (!notice) return null\n const lines: string[] = []\n const still = notice.released.filter(r => !r.control).map(r => r.part)\n if (still.length) lines.push(say('figure.text.removal-released', { parts: still.join(', ') }))\n for (const r of notice.released.filter(r => r.control)) lines.push(say('figure.text.removal-released-motion', { part: r.part, control: r.control! }))\n for (const c of notice.controls) lines.push(say('figure.text.removal-own-control', { part: c.part, control: c.control, min: numberOf(c.min), max: numberOf(c.max) }))\n const fixed = [...new Set(notice.fixed.map(f => f.part))]\n if (fixed.length) lines.push(say('figure.text.removal-fixed', { parts: fixed.join(', ') }))\n if (notice.bindings?.length) lines.push(say('figure.text.removal-bindings', { places: notice.bindings.map(b => b.label ?? b.id).join(', ') }))\n if (notice.mountingFace) lines.push(say('figure.text.removal-mounting-face', {}))\n return lines.length ? lines.join(' ') : null\n}\n\n/**\n * A recipe refused at one of its steps: which step, and why -- the particular sentence when there is one (a size\n * range, a value's range, a placement), otherwise the kernel's code. The step is the refusal's path, `steps[2]`: the\n * contract's path grammar, not its English (ADR-0127 decision 6).\n */\nexport function recipeRefusalOf(error: unknown, say: Say): string | null {\n const step = /^steps\\[(\\d+)\\]$/.exec((error as { path?: string })?.path ?? '')\n if (!step) return null\n const why = sizeRangeRefusalOf(error, say) ?? inputRangeRefusalOf(error, say) ?? placementRefusalOf(error, say)\n return say('figure.text.recipe-step-refused', { step: String(Number(step[1]) + 1), why: why ?? '', code: codeOf(error) ?? '' })\n}\n\n/**\n * A corner or an inside the part cannot take (ADR-0100 stage 1): what was too large or too thick, or what holds on\n * to what the edit would take away.\n */\nfunction sectionRefusalOf(error: unknown, say: Say): string | null {\n const mapping = detailsOf(error, 'faces-taken-away')\n if (mapping) return say('figure.text.section-face-in-use', { faces: mapping.lost.map(l => say('figure.label.face-' + l.face, {})).join(', ') })\n if (codeOf(error) === 'DIMENSION_LINKED') return say('figure.text.section-dimension-linked', {})\n if (detailsOf(error, 'section-invalid')?.issues.some(i => i.code === 'CORNER_TOO_LARGE')) return say('figure.text.section-corner-too-large', {})\n const inside = detailsOf(error, 'inside-invalid')?.refusal\n if (inside?.code === 'CAVITY' && inside.refused === 'NO_ROOM_INSIDE') return say('figure.text.section-wall-too-thick', {})\n if (inside?.code === 'CAVITY_NO_LENGTH') return say('figure.text.section-ends-too-thick', {})\n return null\n}\n\n/**\n * A slot layout refused (ADR-0118): the anchor, slot or value it was refused for. The layout's own findings are named\n * by where they are; the editor checks them before Apply, so they rarely reach here.\n */\nexport function slotLayoutRefusalOf(error: unknown, say: Say): string | null {\n if (detailsOf(error, 'slot-layout-label-missing')) return say('figure.text.slot-layout-label-missing', {})\n if (detailsOf(error, 'slot-anchors-missing')) return say('figure.text.slot-anchors-missing', {})\n const twice = detailsOf(error, 'slot-anchor-duplicate')\n if (twice) return say('figure.text.slot-anchor-duplicate', { anchor: twice.anchor })\n const flat = detailsOf(error, 'slot-anchor-not-flat')\n if (flat) return say('figure.text.slot-anchor-not-flat', { anchor: flat.anchor, part: flat.part })\n const gone = detailsOf(error, 'slot-anchor-no-part')\n if (gone) return say('figure.text.slot-anchor-no-part', { anchor: gone.anchor, part: gone.part })\n const issues = detailsOf(error, 'slot-layout-issues')\n if (issues) return say('figure.text.slot-layout-issues', { path: issues.issues[0]?.path ?? '' })\n const empty = detailsOf(error, 'slot-accepts-empty')\n if (empty) return say('figure.text.slot-accepts-empty', { slot: empty.slot })\n const taken = detailsOf(error, 'slot-id-taken')\n if (taken) return say('figure.text.slot-id-taken', { slot: taken.slot })\n return null\n}\n\n/** The figure's limits: its nodes, its size saved, how deep it nests. */\nfunction documentLimitRefusalOf(error: unknown, say: Say): string | null {\n if (codeOf(error) !== 'DOCUMENT_LIMIT') return null\n const nodes = detailsOf(error, 'node-limit')\n if (nodes) return say('figure.text.edit-refused-node-limit', { max: String(nodes.max) })\n const large = detailsOf(error, 'document-too-large')\n if (large)\n return large.at === undefined\n ? say('figure.text.document-too-large-unmeasured', { max: kibOf(large.max) })\n : say('figure.text.document-too-large', { max: kibOf(large.max), at: kibOf(large.at) })\n const deep = detailsOf(error, 'nesting-too-deep')\n if (deep) return say('figure.text.document-nesting-too-deep', { max: String(deep.max), at: String(deep.at) })\n return null\n}\n\n/**\n * A refusal in the author's words when the screen has words for it, otherwise said as a refusal with its code -- never\n * the kernel's English on the screen (the duplicate of a row's part showed 「EDIT_TARGET: … not a repeated template」,\n * 2026-09-27).\n */\nexport function editRefusalOf(error: unknown, say: Say): string {\n return (\n sizeRangeRefusalOf(error, say) ??\n inputRangeRefusalOf(error, say) ??\n repeatPitchRefusalOf(error, say) ??\n rowLimitRefusalOf(error, say) ??\n placementRefusalOf(error, say) ??\n partNameRefusalOf(error, say) ??\n documentLimitRefusalOf(error, say) ??\n sectionRefusalOf(error, say) ??\n slotLayoutRefusalOf(error, say) ??\n say('figure.text.edit-refused', { code: codeOf(error) ?? '' })\n )\n}\n\n/**\n * A value outside the range its input declares, with the range and the value given. The figure's own size is named by\n * its axis; any other input by its range only.\n */\nexport function inputRangeRefusalOf(error: unknown, say: Say): string | null {\n if (codeOf(error) !== 'INPUT_RANGE') return null\n const range = detailsOf(error, 'value-outside-range')\n if (!range) return null\n const axis = (Object.entries(FIGURE_INSTANCE_SIZE_INPUTS) as Array<[string, string]>).find(([, id]) => id === range.input)?.[0]\n const params = { value: numberOf(range.value), min: numberOf(range.min), max: numberOf(range.max) }\n return axis ? say('figure.text.input-range-size', { ...params, axis: axis.toUpperCase() }) : say('figure.text.input-range', params)\n}\n\n/**\n * A row past its limits: a pitch so fine it would hold more copies than a row takes, a row that would expand to more\n * bodies than a figure draws, or a number of copies outside what a row may have.\n */\nexport function rowLimitRefusalOf(error: unknown, say: Say): string | null {\n const copies = detailsOf(error, 'copies-over-limit')\n if (copies) return say('figure.text.row-copies-over-limit', { count: copies.count.toLocaleString(), limit: copies.limit.toLocaleString() })\n const bodies = detailsOf(error, 'geometry-over-limit')\n if (bodies) return say('figure.text.row-geometry-over-limit', { count: bodies.count.toLocaleString(), limit: bodies.limit.toLocaleString() })\n const count = detailsOf(error, 'row-copies-out-of-range')\n if (count) return say('figure.text.row-copies-out-of-range', { count: count.count.toLocaleString(), min: String(count.min), max: String(count.max) })\n return null\n}\n\n/** A row's pitch under which the figure, at the length it is authored, would hold more copies than a row takes. */\nexport function repeatPitchRefusalOf(error: unknown, say: Say): string | null {\n if (codeOf(error) !== 'INPUT_RANGE') return null\n const pitch = detailsOf(error, 'pitch-too-many-copies')\n if (!pitch) return null\n return say('figure.text.repeat-pitch-too-small', { length: pitch.length.toLocaleString(), min: String(pitch.least), limit: String(pitch.limit) })\n}\n\n/**\n * Why \"follow the size and keep where the figure is placed\" was not applied, in the author's words (ADR-0097): the plan\n * says what it would have had to overwrite, and for a part through the plane how far. A code the screen has no words\n * for is said as a refusal with its code, never in the kernel's English.\n */\nexport function resizeRefusalOf(plan: { mode: string; refusal?: { code: string; axis?: string; mm?: number } }, part: string, say: Say): string {\n const refusal = plan.refusal\n if (!refusal) return ''\n const place = say(`figure.label.resize-place-${plan.mode}`, {})\n const params = { part, place, axis: (refusal.axis ?? '').toUpperCase(), mm: refusal.mm === undefined ? '' : String(Math.round(refusal.mm)) }\n const known = ['HELD', 'TURNED', 'UNIFORM_POLICY', 'SHAPE_EDIT', 'DIMENSION_RULE', 'POSITION_RULE', 'GAP_CHOICE', 'NO_FACE']\n if (known.includes(refusal.code)) return say(`figure.text.resize-refused-${refusal.code.toLowerCase().replace(/_/g, '-')}`, params)\n return say('figure.text.edit-refused', { code: refusal.code })\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { FigureCavityRequest, FigureEvaluatedShape } from '@hatiolab/figure-model';
1
+ import type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape } from '@hatiolab/figure-model';
2
2
  type Axis = 'x' | 'y' | 'z';
3
3
  type End = 'start' | 'end';
4
4
  /** The face each side of a section is, and each end of a push: a push's start is its low side. */
@@ -18,6 +18,8 @@ export declare function defaultWallOf(shape: FigureEvaluatedShape): number;
18
18
  export declare function cavityRequestOf(shape: FigureEvaluatedShape, patch?: Partial<FigureCavityRequest>): FigureCavityRequest;
19
19
  /** The most a rectangle's corners can reach: half its narrower side (the kernel's CORNER_TOO_LARGE says where). */
20
20
  export declare function cornerLimitOf(shape: FigureEvaluatedShape): number | undefined;
21
+ /** A corner radius as the one command: 0 takes the rounding away. */
22
+ export declare const cornerActionOf: (part: string, radius: number) => FigureAuthoringAction;
21
23
  /** Whether a corner radius can be taken; if not, the most it can be. */
22
24
  export declare function cornerRefusalOf(shape: FigureEvaluatedShape, radius: number): {
23
25
  max: number;
@@ -37,6 +39,20 @@ export type FigureCavityAsk = {
37
39
  };
38
40
  /** Whether an inside can be taken, asked of the kernel; if not, what to change and the most it can be. */
39
41
  export declare function cavityRefusalOf(shape: FigureEvaluatedShape, request: FigureCavityRequest): FigureCavityAsk | null;
42
+ /**
43
+ * What the kernel would refuse of an inside, as words: an i18n key and its values; null when it would take it. For one
44
+ * side's wall with the walls one per side, the most is that side's with the opposite kept, not the kernel's all-round one.
45
+ */
46
+ export declare function cavityRefusalWordsOf(shape: FigureEvaluatedShape, request: {
47
+ wall: Record<string, number>;
48
+ start: FigureCavityRequest['start'];
49
+ end: FigureCavityRequest['end'];
50
+ }, perSide: boolean, side?: string): {
51
+ key: string;
52
+ params: Record<string, string>;
53
+ } | null;
54
+ /** Whether a part can have an inside: a pushed rectangle or ellipse (a drawn section's is a later stage). */
55
+ export declare const hollowableOf: (shape: FigureEvaluatedShape) => boolean;
40
56
  /** What the inside makes of the part (§3.3): open at both ends a pipe, at one a container, at neither a closed space. */
41
57
  export declare function cavityResultOf(cavity: NonNullable<FigureEvaluatedShape['cavity']>): 'pipe' | 'container' | 'sealed';
42
58
  /** How deep the inside is along the push: the length less the closed ends. */
@@ -44,6 +44,8 @@ export function cornerLimitOf(shape) {
44
44
  const maxes = issues.flatMap(i => (i.code === 'CORNER_TOO_LARGE' ? [i.max] : []));
45
45
  return maxes.length ? Math.min(...maxes) : undefined;
46
46
  }
47
+ /** A corner radius as the one command: 0 takes the rounding away. */
48
+ export const cornerActionOf = (part, radius) => ({ kind: 'set-section-corner', part, corner: radius > 0 ? radius : null });
47
49
  /** Whether a corner radius can be taken; if not, the most it can be. */
48
50
  export function cornerRefusalOf(shape, radius) {
49
51
  const e = shape.extrusion;
@@ -77,6 +79,22 @@ export function cavityRefusalOf(shape, request) {
77
79
  return { code: 'ends-too-thick', max: mm(e.end - e.start) };
78
80
  return { code: 'not-positive' };
79
81
  }
82
+ /**
83
+ * What the kernel would refuse of an inside, as words: an i18n key and its values; null when it would take it. For one
84
+ * side's wall with the walls one per side, the most is that side's with the opposite kept, not the kernel's all-round one.
85
+ */
86
+ export function cavityRefusalWordsOf(shape, request, perSide, side) {
87
+ const ask = cavityRefusalOf(shape, { wall: { ...request.wall }, start: request.start, end: request.end });
88
+ if (!ask)
89
+ return null;
90
+ if (ask.code === 'wall-too-thick')
91
+ return { key: 'figure.text.section-wall-over', params: { max: String(perSide && side ? mm(sideWallLimitOf(shape, request.wall, side)) : ask.max) } };
92
+ if (ask.code === 'ends-too-thick')
93
+ return { key: 'figure.text.section-ends-over', params: { max: String(ask.max) } };
94
+ return { key: 'figure.text.section-not-positive', params: {} };
95
+ }
96
+ /** Whether a part can have an inside: a pushed rectangle or ellipse (a drawn section's is a later stage). */
97
+ export const hollowableOf = (shape) => shape.extrusion?.section.kind === 'rectangle' || shape.extrusion?.section.kind === 'ellipse';
80
98
  /** What the inside makes of the part (§3.3): open at both ends a pipe, at one a container, at neither a closed space. */
81
99
  export function cavityResultOf(cavity) {
82
100
  const open = [cavity.start, cavity.end].filter(e => e === 'open').length;