@ethlete/cli 3.0.0-next.23 → 3.0.0-next.25

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 (202) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/design/contrast.ts +49 -0
  3. package/design/define-call.ts +48 -8
  4. package/design/define-part.ts +83 -1
  5. package/design/embed-page.ts +37 -4
  6. package/design/icon-sheet.ts +151 -0
  7. package/design/mark-part.ts +79 -2
  8. package/design/morph.ts +67 -0
  9. package/design/motion-runtime.ts +407 -0
  10. package/design/spring.ts +53 -0
  11. package/design/token-sheet.ts +87 -0
  12. package/design/web/env.d.ts +6 -2
  13. package/design/web/frame.ts +159 -6
  14. package/package.json +2 -1
  15. package/src/lib/design/calls-tsconfig.js +1 -2
  16. package/src/lib/design/calls-tsconfig.js.map +1 -1
  17. package/src/lib/design/changed-parts.d.ts +4 -4
  18. package/src/lib/design/changed-parts.js +10 -6
  19. package/src/lib/design/changed-parts.js.map +1 -1
  20. package/src/lib/design/contact-sheet.d.ts +26 -13
  21. package/src/lib/design/contact-sheet.js +122 -40
  22. package/src/lib/design/contact-sheet.js.map +1 -1
  23. package/src/lib/design/design-command.js +50 -2
  24. package/src/lib/design/design-command.js.map +1 -1
  25. package/src/lib/design/force-interactions.d.ts +2 -1
  26. package/src/lib/design/force-interactions.js +7 -4
  27. package/src/lib/design/force-interactions.js.map +1 -1
  28. package/src/lib/design/generated-stylesheets.d.ts +15 -0
  29. package/src/lib/design/generated-stylesheets.js +52 -0
  30. package/src/lib/design/generated-stylesheets.js.map +1 -0
  31. package/src/lib/design/inbox-command.d.ts +1 -0
  32. package/src/lib/design/inbox-command.js +15 -0
  33. package/src/lib/design/inbox-command.js.map +1 -1
  34. package/src/lib/design/mcp-command.d.ts +60 -0
  35. package/src/lib/design/mcp-command.js +327 -0
  36. package/src/lib/design/mcp-command.js.map +1 -0
  37. package/src/lib/design/merge-compare.d.ts +10 -0
  38. package/src/lib/design/merge-compare.js +17 -4
  39. package/src/lib/design/merge-compare.js.map +1 -1
  40. package/src/lib/design/motion-command.d.ts +71 -0
  41. package/src/lib/design/motion-command.js +314 -0
  42. package/src/lib/design/motion-command.js.map +1 -0
  43. package/src/lib/design/motion-endpoint.d.ts +61 -0
  44. package/src/lib/design/motion-endpoint.js +133 -0
  45. package/src/lib/design/motion-endpoint.js.map +1 -0
  46. package/src/lib/design/motion-flow.d.ts +5 -0
  47. package/src/lib/design/motion-flow.js +29 -0
  48. package/src/lib/design/motion-flow.js.map +1 -0
  49. package/src/lib/design/motion-shot.d.ts +43 -0
  50. package/src/lib/design/motion-shot.js +97 -0
  51. package/src/lib/design/motion-shot.js.map +1 -0
  52. package/src/lib/design/paths.d.ts +11 -0
  53. package/src/lib/design/paths.js.map +1 -1
  54. package/src/lib/design/ready-shots.d.ts +7 -0
  55. package/src/lib/design/ready-shots.js +22 -1
  56. package/src/lib/design/ready-shots.js.map +1 -1
  57. package/src/lib/design/render-packages.d.ts +9 -0
  58. package/src/lib/design/render-packages.js +13 -3
  59. package/src/lib/design/render-packages.js.map +1 -1
  60. package/src/lib/design/render.js +3 -3
  61. package/src/lib/design/render.js.map +1 -1
  62. package/src/lib/design/serve.js +108 -21
  63. package/src/lib/design/serve.js.map +1 -1
  64. package/src/lib/design/shot-command.d.ts +12 -6
  65. package/src/lib/design/shot-command.js +60 -48
  66. package/src/lib/design/shot-command.js.map +1 -1
  67. package/src/lib/design/shot.d.ts +30 -4
  68. package/src/lib/design/shot.js +138 -53
  69. package/src/lib/design/shot.js.map +1 -1
  70. package/src/lib/design/sketch-command.js +132 -39
  71. package/src/lib/design/sketch-command.js.map +1 -1
  72. package/src/lib/design/sketch-stylesheets.d.ts +7 -0
  73. package/src/lib/design/sketch-stylesheets.js +63 -0
  74. package/src/lib/design/sketch-stylesheets.js.map +1 -0
  75. package/src/lib/design/studio-api.d.ts +28 -6
  76. package/src/lib/design/studio-api.js +102 -17
  77. package/src/lib/design/studio-api.js.map +1 -1
  78. package/src/lib/design/system/check-system.js +8 -0
  79. package/src/lib/design/system/check-system.js.map +1 -1
  80. package/src/lib/design/system/comments/comment.d.ts +17 -0
  81. package/src/lib/design/system/comments/comment.js +35 -1
  82. package/src/lib/design/system/comments/comment.js.map +1 -1
  83. package/src/lib/design/system/comments/complete.js +4 -2
  84. package/src/lib/design/system/comments/complete.js.map +1 -1
  85. package/src/lib/design/system/complete-command.d.ts +9 -0
  86. package/src/lib/design/system/complete-command.js +134 -0
  87. package/src/lib/design/system/complete-command.js.map +1 -0
  88. package/src/lib/design/system/complete.d.ts +171 -0
  89. package/src/lib/design/system/complete.js +1106 -0
  90. package/src/lib/design/system/complete.js.map +1 -0
  91. package/src/lib/design/system/contrast-check.d.ts +26 -0
  92. package/src/lib/design/system/contrast-check.js +153 -0
  93. package/src/lib/design/system/contrast-check.js.map +1 -0
  94. package/src/lib/design/system/exceptions.d.ts +59 -0
  95. package/src/lib/design/system/exceptions.js +132 -0
  96. package/src/lib/design/system/exceptions.js.map +1 -0
  97. package/src/lib/design/system/flows/flow.d.ts +3 -0
  98. package/src/lib/design/system/flows/flow.js +5 -3
  99. package/src/lib/design/system/flows/flow.js.map +1 -1
  100. package/src/lib/design/system/handoff.d.ts +11 -0
  101. package/src/lib/design/system/handoff.js +30 -0
  102. package/src/lib/design/system/handoff.js.map +1 -0
  103. package/src/lib/design/system/imports.d.ts +28 -3
  104. package/src/lib/design/system/imports.js +84 -7
  105. package/src/lib/design/system/imports.js.map +1 -1
  106. package/src/lib/design/system/inventory-approval.d.ts +41 -0
  107. package/src/lib/design/system/inventory-approval.js +71 -0
  108. package/src/lib/design/system/inventory-approval.js.map +1 -0
  109. package/src/lib/design/system/inventory.d.ts +65 -0
  110. package/src/lib/design/system/inventory.js +168 -0
  111. package/src/lib/design/system/inventory.js.map +1 -0
  112. package/src/lib/design/system/list-system.d.ts +11 -0
  113. package/src/lib/design/system/list-system.js +26 -3
  114. package/src/lib/design/system/list-system.js.map +1 -1
  115. package/src/lib/design/system/product-stylesheets.d.ts +3 -0
  116. package/src/lib/design/system/product-stylesheets.js +40 -0
  117. package/src/lib/design/system/product-stylesheets.js.map +1 -0
  118. package/src/lib/design/system/render-check.js +30 -4
  119. package/src/lib/design/system/render-check.js.map +1 -1
  120. package/src/lib/design/system/resolve-product.d.ts +2 -3
  121. package/src/lib/design/system/resolve-product.js +4 -6
  122. package/src/lib/design/system/resolve-product.js.map +1 -1
  123. package/src/lib/design/system/rules/canonical-class.d.ts +9 -0
  124. package/src/lib/design/system/rules/canonical-class.js +132 -0
  125. package/src/lib/design/system/rules/canonical-class.js.map +1 -0
  126. package/src/lib/design/system/rules/inline-svg.d.ts +7 -0
  127. package/src/lib/design/system/rules/inline-svg.js +28 -0
  128. package/src/lib/design/system/rules/inline-svg.js.map +1 -0
  129. package/src/lib/design/system/rules/motion.d.ts +4 -0
  130. package/src/lib/design/system/rules/motion.js +46 -2
  131. package/src/lib/design/system/rules/motion.js.map +1 -1
  132. package/src/lib/design/system/rules/stale-replace.js +41 -2
  133. package/src/lib/design/system/rules/stale-replace.js.map +1 -1
  134. package/src/lib/design/system/rules/token-selectors.js +1 -1
  135. package/src/lib/design/system/rules/token-selectors.js.map +1 -1
  136. package/src/lib/design/system/rules/utility-css.d.ts +11 -0
  137. package/src/lib/design/system/rules/utility-css.js +290 -0
  138. package/src/lib/design/system/rules/utility-css.js.map +1 -0
  139. package/src/lib/design/system/sketch/baseline.d.ts +3 -2
  140. package/src/lib/design/system/sketch/baseline.js +10 -4
  141. package/src/lib/design/system/sketch/baseline.js.map +1 -1
  142. package/src/lib/design/system/sketch/host-edit.d.ts +4 -0
  143. package/src/lib/design/system/sketch/host-edit.js +68 -0
  144. package/src/lib/design/system/sketch/host-edit.js.map +1 -0
  145. package/src/lib/design/system/sketch/merge-preview.d.ts +4 -2
  146. package/src/lib/design/system/sketch/merge-preview.js +20 -3
  147. package/src/lib/design/system/sketch/merge-preview.js.map +1 -1
  148. package/src/lib/design/system/sketch/merge-shared.d.ts +42 -6
  149. package/src/lib/design/system/sketch/merge-shared.js +122 -24
  150. package/src/lib/design/system/sketch/merge-shared.js.map +1 -1
  151. package/src/lib/design/system/sketch/merge.d.ts +6 -5
  152. package/src/lib/design/system/sketch/merge.js +95 -35
  153. package/src/lib/design/system/sketch/merge.js.map +1 -1
  154. package/src/lib/design/system/sketch/merged-parts.d.ts +17 -0
  155. package/src/lib/design/system/sketch/merged-parts.js +35 -2
  156. package/src/lib/design/system/sketch/merged-parts.js.map +1 -1
  157. package/src/lib/design/system/sketch/no-visible-change.d.ts +10 -3
  158. package/src/lib/design/system/sketch/no-visible-change.js +75 -20
  159. package/src/lib/design/system/sketch/no-visible-change.js.map +1 -1
  160. package/src/lib/design/system/sketch/overlay.js +16 -3
  161. package/src/lib/design/system/sketch/overlay.js.map +1 -1
  162. package/src/lib/design/system/sketch/part-definition.d.ts +12 -0
  163. package/src/lib/design/system/sketch/part-definition.js +40 -1
  164. package/src/lib/design/system/sketch/part-definition.js.map +1 -1
  165. package/src/lib/design/system/sketch/sketch.d.ts +40 -3
  166. package/src/lib/design/system/sketch/sketch.js +147 -50
  167. package/src/lib/design/system/sketch/sketch.js.map +1 -1
  168. package/src/lib/design/system/sketch/unchanged-states.d.ts +10 -4
  169. package/src/lib/design/system/sketch/unchanged-states.js +37 -23
  170. package/src/lib/design/system/sketch/unchanged-states.js.map +1 -1
  171. package/src/lib/design/system/sketch/unused-closure.d.ts +12 -0
  172. package/src/lib/design/system/sketch/unused-closure.js +185 -0
  173. package/src/lib/design/system/sketch/unused-closure.js.map +1 -0
  174. package/src/lib/design/system/system-modules.d.ts +5 -1
  175. package/src/lib/design/system/system-modules.js +32 -17
  176. package/src/lib/design/system/system-modules.js.map +1 -1
  177. package/src/lib/design/system/system-tsconfig.d.ts +2 -1
  178. package/src/lib/design/system/system-tsconfig.js +11 -6
  179. package/src/lib/design/system/system-tsconfig.js.map +1 -1
  180. package/src/lib/design/thumb.d.ts +6 -2
  181. package/src/lib/design/thumb.js +36 -15
  182. package/src/lib/design/thumb.js.map +1 -1
  183. package/src/lib/design/variant-diff.d.ts +12 -10
  184. package/src/lib/design/variant-diff.js +14 -13
  185. package/src/lib/design/variant-diff.js.map +1 -1
  186. package/src/lib/design/warm-pages.d.ts +20 -0
  187. package/src/lib/design/warm-pages.js +78 -0
  188. package/src/lib/design/warm-pages.js.map +1 -0
  189. package/src/lib/update/commits.d.ts +9 -0
  190. package/src/lib/update/commits.js +15 -1
  191. package/src/lib/update/commits.js.map +1 -1
  192. package/src/lib/update/migration-manifest.d.ts +6 -0
  193. package/src/lib/update/migration-manifest.js +7 -0
  194. package/src/lib/update/migration-manifest.js.map +1 -1
  195. package/src/lib/update/migrations-command.js +1 -0
  196. package/src/lib/update/migrations-command.js.map +1 -1
  197. package/src/lib/update/run-migrations.d.ts +22 -0
  198. package/src/lib/update/run-migrations.js +60 -1
  199. package/src/lib/update/run-migrations.js.map +1 -1
  200. package/src/lib/update/update-command.d.ts +10 -0
  201. package/src/lib/update/update-command.js +28 -2
  202. package/src/lib/update/update-command.js.map +1 -1
@@ -0,0 +1,1106 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.completenessOf = exports.inventoryIdsOf = exports.seePart = exports.completenessGapLineOf = exports.completenessGapsOf = exports.findingKeyOf = exports.isFindingOf = exports.declaredControlsOf = void 0;
13
+ const fs_1 = require("fs");
14
+ const path_1 = require("path");
15
+ const browser_1 = require("../browser");
16
+ const force_interactions_1 = require("../force-interactions");
17
+ const serve_1 = require("../serve");
18
+ const shot_1 = require("../shot");
19
+ const thumb_1 = require("../thumb");
20
+ const resolve_product_1 = require("./resolve-product");
21
+ const baseline_1 = require("./sketch/baseline");
22
+ const merged_parts_1 = require("./sketch/merged-parts");
23
+ const system_modules_1 = require("./system-modules");
24
+ const exceptions_1 = require("./exceptions");
25
+ const inventory_approval_1 = require("./inventory-approval");
26
+ const KINDS = {
27
+ disclosure: { surface: 'body', closed: 'collapsed' },
28
+ button: { adds: ['active'] },
29
+ select: { surface: 'open', options: true },
30
+ menu: { surface: 'open', options: true },
31
+ row: { selects: true, virtualFocus: true },
32
+ field: { noActive: true },
33
+ tooltip: { surface: 'tooltip' },
34
+ };
35
+ const CHECKED_KINDS = Object.keys(KINDS);
36
+ const INPUT_INTERACTIONS = { pointer: ['hover', 'active'], keyboard: ['focus-visible'] };
37
+ const MARKS = {
38
+ selected: 'aria-selected="true", aria-checked="true", aria-pressed="true" or aria-current',
39
+ disabled: 'disabled or aria-disabled="true"',
40
+ };
41
+ const CONTROL_MARKS = Object.assign(Object.assign({}, MARKS), { disabled: `${MARKS.disabled} on it or a data-et-control-part in it` });
42
+ const isRecord = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
43
+ const requiredInteractionsOf = (control) => {
44
+ var _a, _b;
45
+ return [
46
+ ...new Set([
47
+ ...control.input
48
+ .flatMap((input) => { var _a; return (_a = INPUT_INTERACTIONS[input]) !== null && _a !== void 0 ? _a : []; })
49
+ .filter((interaction) => { var _a; return !(((_a = KINDS[control.kind]) === null || _a === void 0 ? void 0 : _a.noActive) && interaction === 'active'); }),
50
+ ...((_b = (_a = KINDS[control.kind]) === null || _a === void 0 ? void 0 : _a.adds) !== null && _b !== void 0 ? _b : []),
51
+ ]),
52
+ ];
53
+ };
54
+ const gridGapOf = (options) => {
55
+ const { grid, states, interactions } = options;
56
+ const fix = `draw its states with interactionRows, which gives the grid a column per interaction (${interactions.join(', ')})`;
57
+ if (!isRecord(grid) || !Array.isArray(grid['columns']) || !isRecord(grid['rows']))
58
+ return `the part has no grid - ${fix}`;
59
+ const columns = grid['columns'];
60
+ const missing = interactions.filter((interaction) => !columns.includes(interaction));
61
+ if (missing.length > 0)
62
+ return `its grid has no column ${missing.join(', ')} - ${fix}`;
63
+ const holes = Object.entries(grid['rows']).flatMap(([row, cells]) => interactions
64
+ .filter((interaction) => {
65
+ const state = isRecord(cells) ? cells[interaction] : undefined;
66
+ return typeof state !== 'string' || !states.includes(state);
67
+ })
68
+ .map((interaction) => `${row} ${interaction}`));
69
+ return holes.length > 0 ? `its grid draws no state in ${holes.join(', ')} - ${fix}` : null;
70
+ };
71
+ const declaredControlsOf = (value) => isRecord(value)
72
+ ? Object.fromEntries(Object.entries(value).map(([id, control]) => {
73
+ const declared = isRecord(control) ? control : {};
74
+ return [
75
+ id,
76
+ {
77
+ kind: typeof declared['kind'] === 'string' ? declared['kind'] : '',
78
+ part: typeof declared['part'] === 'string' ? declared['part'] : null,
79
+ input: Array.isArray(declared['input'])
80
+ ? declared['input'].filter((input) => typeof input === 'string')
81
+ : [],
82
+ surfaces: isRecord(declared['surfaces'])
83
+ ? Object.fromEntries(Object.entries(declared['surfaces']).filter((entry) => typeof entry[1] === 'string'))
84
+ : {},
85
+ disabled: declared['disabled'] === true,
86
+ },
87
+ ];
88
+ }))
89
+ : null;
90
+ exports.declaredControlsOf = declaredControlsOf;
91
+ /** Whether a discovered element is an undeclared or unclassified finding of the part, not owned or declared. */
92
+ const isFindingOf = (declared) => (found) => {
93
+ var _a;
94
+ return ((_a = found.owner) !== null && _a !== void 0 ? _a : null) === null &&
95
+ !found.within.some((id) => { var _a, _b; return ((_b = (_a = declared[id]) === null || _a === void 0 ? void 0 : _a.part) !== null && _b !== void 0 ? _b : null) !== null; }) &&
96
+ !(found.kind === 'control' && found.marked !== null);
97
+ };
98
+ exports.isFindingOf = isFindingOf;
99
+ const findingKeyOf = (found) => `${found.kind} ${found.what} ${found.path}`;
100
+ exports.findingKeyOf = findingKeyOf;
101
+ const discoveryGapsOf = (options) => {
102
+ var _a, _b, _c, _d;
103
+ const { part, declared, frames } = options;
104
+ const isFinding = (0, exports.isFindingOf)(declared);
105
+ const groups = new Map();
106
+ for (const frame of frames.filter((seen) => seen.interaction === null)) {
107
+ const counts = new Map();
108
+ for (const found of (_a = frame.found) !== null && _a !== void 0 ? _a : []) {
109
+ if (!isFinding(found))
110
+ continue;
111
+ const key = (0, exports.findingKeyOf)(found);
112
+ const group = (_b = groups.get(key)) !== null && _b !== void 0 ? _b : { found, states: [], count: 0 };
113
+ counts.set(key, ((_c = counts.get(key)) !== null && _c !== void 0 ? _c : 0) + 1);
114
+ if (!group.states.includes(frame.state))
115
+ group.states.push(frame.state);
116
+ group.count = Math.max(group.count, (_d = counts.get(key)) !== null && _d !== void 0 ? _d : 0);
117
+ groups.set(key, group);
118
+ }
119
+ }
120
+ return [...groups.values()]
121
+ .sort((a, b) => a.found.path.localeCompare(b.found.path) || a.found.what.localeCompare(b.found.what))
122
+ .map(({ found, states, count }) => {
123
+ const where = `${found.what} at ${found.path} in ${statesShownOf(states)}${count > 1 ? ` (${count} of them)` : ''}`;
124
+ return found.kind === 'control'
125
+ ? {
126
+ code: 'CONTROL-UNDECLARED',
127
+ target: part,
128
+ detail: `${where} - mark it with data-et-control and declare it in controls`,
129
+ }
130
+ : {
131
+ code: 'CONTROL-UNCLASSIFIED',
132
+ target: part,
133
+ detail: `${where} - draw it as a native control or give it an interactive role and declare it, or drop the pointer cursor and :hover style`,
134
+ };
135
+ });
136
+ };
137
+ const statesShownOf = (states) => states.length > 4 ? `${states.slice(0, 3).join(', ')} and ${states.length - 3} more` : states.join(', ');
138
+ const overrideGapsOf = (options) => {
139
+ var _a, _b;
140
+ const groups = new Map();
141
+ for (const frame of options.frames.filter((seen) => seen.interaction === null))
142
+ for (const override of (_a = frame.overrides) !== null && _a !== void 0 ? _a : []) {
143
+ const key = `${override.owner} ${override.selector} ${override.path}`;
144
+ const group = (_b = groups.get(key)) !== null && _b !== void 0 ? _b : { override, states: [] };
145
+ if (!group.states.includes(frame.state))
146
+ group.states.push(frame.state);
147
+ groups.set(key, group);
148
+ }
149
+ return [...groups.values()]
150
+ .sort((a, b) => a.override.owner.localeCompare(b.override.owner) || a.override.path.localeCompare(b.override.path))
151
+ .map(({ override, states }) => ({
152
+ code: 'CONTROL-OVERRIDDEN',
153
+ target: options.part,
154
+ detail: `"${override.selector}" sets ${override.properties.join(', ')} on ${override.path}, drawn by ${override.owner}, in ${statesShownOf(states)} - change ${override.owner} instead, or mark the control with data-et-control and declare it in controls`,
155
+ }));
156
+ };
157
+ const ownerGapsOf = (options) => {
158
+ var _a, _b, _c;
159
+ const { part, declared, frames, referenced } = options;
160
+ const named = new Set(Object.values(declared).map((control) => control.part));
161
+ const owned = new Map();
162
+ for (const frame of frames.filter((seen) => seen.interaction === null))
163
+ for (const found of (_a = frame.found) !== null && _a !== void 0 ? _a : []) {
164
+ const owner = (_b = found.owner) !== null && _b !== void 0 ? _b : null;
165
+ if (owner === null || named.has(owner))
166
+ continue;
167
+ owned.set(owner, ((_c = owned.get(owner)) !== null && _c !== void 0 ? _c : new Set()).add(`${found.what} ${found.path}`));
168
+ }
169
+ return [...owned.entries()]
170
+ .sort(([a], [b]) => a.localeCompare(b))
171
+ .flatMap(([owner, controls]) => {
172
+ const used = referenced[owner];
173
+ const drawn = `${owner} draws ${controls.size} control(s) here`;
174
+ if (typeof used === 'string')
175
+ return [{ code: 'CONTROL-PART-INCOMPLETE', target: part, detail: `${drawn}: ${used}` }];
176
+ if (!used || used.length === 0)
177
+ return [];
178
+ return [
179
+ {
180
+ code: 'CONTROL-PART-INCOMPLETE',
181
+ target: part,
182
+ detail: `${drawn} and is not design complete: ${used.length} gap(s) - run design complete ${owner}`,
183
+ },
184
+ ];
185
+ });
186
+ };
187
+ const ownersOf = (frames) => [
188
+ ...new Set(frames
189
+ .filter((seen) => seen.interaction === null)
190
+ .flatMap((seen) => { var _a; return ((_a = seen.found) !== null && _a !== void 0 ? _a : []).map((found) => { var _a; return (_a = found.owner) !== null && _a !== void 0 ? _a : null; }); })
191
+ .filter((owner) => owner !== null)),
192
+ ];
193
+ const interactionGapOf = (options) => {
194
+ var _a;
195
+ const { frames, id, interaction } = options;
196
+ const forced = frames.flatMap((frame) => frame.controls
197
+ .filter((control) => control.id === id)
198
+ .flatMap((control) => control.forced.filter((force) => force.interaction === interaction))
199
+ .map((force) => ({ state: frame.state, differs: force.differs })));
200
+ if (forced.some((force) => force.differs))
201
+ return null;
202
+ if (forced.length > 0)
203
+ return `state ${(_a = forced[0]) === null || _a === void 0 ? void 0 : _a.state} forces ${interaction} on it, but its box draws no different pixel than at rest - if a descendant draws ${interaction}, mark it with data-et-control-part`;
204
+ return `no state draws it ${interaction} - draw a state that forces ${interaction} on the data-et-control element, e.g. with forceInteraction - a data-et-control-part in it takes the force too`;
205
+ };
206
+ const keyboardActiveRowGapOf = (options) => {
207
+ const { instances, forcedGap } = options;
208
+ const active = instances.filter((seen) => seen.keyboard);
209
+ const plain = instances.filter((seen) => !seen.keyboard && !seen.selected && !seen.disabled);
210
+ if (active.length === 0)
211
+ return `${forcedGap}; no state marks it data-active-source="keyboard" either`;
212
+ if (plain.length === 0)
213
+ return `a state marks it data-active-source="keyboard", but no state draws it plain (not selected, active or disabled) to compare it with`;
214
+ if (active.some((seen) => plain.some((other) => other.look !== seen.look)))
215
+ return null;
216
+ return `it looks the same with data-active-source="keyboard" as plain - give the active look its own colours`;
217
+ };
218
+ const stillGapOf = (options) => {
219
+ var _a;
220
+ const { frames, id, interaction } = options;
221
+ for (const frame of frames)
222
+ for (const control of frame.controls.filter((seen) => seen.id === id))
223
+ for (const force of control.forced.filter((seen) => { var _a; return seen.interaction === interaction && ((_a = seen.still) === null || _a === void 0 ? void 0 : _a.length); }))
224
+ return `state ${frame.state} changes ${(_a = force.still) === null || _a === void 0 ? void 0 : _a.join(', ')} in one frame - give them a transition with the product's motion tokens`;
225
+ return null;
226
+ };
227
+ const lookGapOf = (options) => {
228
+ const { seen, flag, what, marks = MARKS } = options;
229
+ const on = seen.filter((one) => one.flag);
230
+ const off = seen.filter((one) => !one.flag);
231
+ if (on.length === 0)
232
+ return `no state draws ${what} ${flag} - mark it with ${marks[flag]} in a state`;
233
+ if (off.length === 0)
234
+ return `every state draws ${what} ${flag} - draw it without ${flag} too, to compare`;
235
+ if (!on.some((one) => off.some((other) => one.look !== other.look)))
236
+ return `${what} looks the same ${flag} as without - give the ${flag} look its own colours`;
237
+ return null;
238
+ };
239
+ const forcedGapOf = (options) => {
240
+ var _a;
241
+ const { forced, what, interaction } = options;
242
+ if (forced.some((force) => force.differs))
243
+ return null;
244
+ if (forced.length > 0)
245
+ return `state ${(_a = forced[0]) === null || _a === void 0 ? void 0 : _a.state} forces ${interaction} on ${what}, but its box draws no different pixel than at rest`;
246
+ return `no state draws ${what} ${interaction} - force ${interaction} on it, e.g. with forceInteraction`;
247
+ };
248
+ const surfaceGapsOf = (options) => {
249
+ const { frames, id, control, states, surface, closed } = options;
250
+ const rest = frames.filter((frame) => frame.interaction === null);
251
+ const state = control.surfaces[surface];
252
+ const surfaceId = `${id}.${surface}`;
253
+ const shows = (frame) => frame.surfaces.some((seen) => seen.id === surfaceId && seen.shown);
254
+ const drawsControl = (frame) => frame.controls.some((seen) => seen.id === id);
255
+ const gaps = [];
256
+ if (closed && !rest.some((frame) => drawsControl(frame) && !shows(frame)))
257
+ gaps.push([closed, `every state that draws it also shows its ${surface} - draw a state with ${surfaceId} closed`]);
258
+ if (state === undefined)
259
+ gaps.push([surface, `declares no surfaces.${surface} - name the state that draws it open`]);
260
+ else if (!states.includes(state))
261
+ gaps.push([surface, `surfaces.${surface} names state ${state}, which the part does not declare`]);
262
+ else if (!rest.some((frame) => frame.state === state && drawsControl(frame) && shows(frame)))
263
+ gaps.push([
264
+ surface,
265
+ `state ${state} draws no visible, non-empty data-et-surface="${surfaceId}" next to data-et-control="${id}"`,
266
+ ]);
267
+ return gaps;
268
+ };
269
+ const KEYBOARD_ACTIVE = 'aria-activedescendant or data-active-source="keyboard"';
270
+ const isKeyboardActive = (option) => !!option.named || !!option.keyboard;
271
+ const isPlain = (option) => !option.selected && !isKeyboardActive(option) && option.forced.length === 0;
272
+ const keyboardActiveGapOf = (options) => {
273
+ var _a, _b;
274
+ const { frames, shownIn, forcedGap } = options;
275
+ const active = frames
276
+ .map((frame) => ({ state: frame.state, options: shownIn(frame) }))
277
+ .filter((frame) => frame.options.some(isKeyboardActive));
278
+ const compared = active.filter((frame) => frame.options.some(isPlain));
279
+ if (active.length === 0)
280
+ return `${forcedGap}; no option is marked active by ${KEYBOARD_ACTIVE} either`;
281
+ if (compared.length === 0)
282
+ return `state ${(_a = active[0]) === null || _a === void 0 ? void 0 : _a.state} marks an option active by ${KEYBOARD_ACTIVE}, but draws no plain option (not selected, active or forced) to compare it with`;
283
+ if (compared.some((frame) => frame.options.some((option) => isKeyboardActive(option) && frame.options.some((plain) => isPlain(plain) && plain.look !== option.look))))
284
+ return null;
285
+ return `state ${(_b = compared[0]) === null || _b === void 0 ? void 0 : _b.state} marks an option active by ${KEYBOARD_ACTIVE}, but it looks the same as a plain option - give the active option its own look`;
286
+ };
287
+ const optionGapsOf = (options) => {
288
+ const { frames, surfaceId } = options;
289
+ const shownIn = (frame) => frame.surfaces.filter((seen) => seen.id === surfaceId && seen.shown).flatMap((seen) => { var _a; return (_a = seen.options) !== null && _a !== void 0 ? _a : []; });
290
+ const what = `an option in ${surfaceId}`;
291
+ const gaps = [];
292
+ for (const interaction of ['hover', 'focus-visible']) {
293
+ const forced = frames.flatMap((frame) => shownIn(frame).flatMap((option) => option.forced
294
+ .filter((force) => force.interaction === interaction)
295
+ .map((force) => ({ state: frame.state, differs: force.differs }))));
296
+ const gap = forcedGapOf({ forced, what, interaction });
297
+ const missing = gap && interaction === 'focus-visible' ? keyboardActiveGapOf({ frames, shownIn, forcedGap: gap }) : gap;
298
+ if (missing)
299
+ gaps.push([`option-${interaction}`, missing]);
300
+ }
301
+ const seen = frames
302
+ .filter((frame) => frame.interaction === null)
303
+ .flatMap((frame) => shownIn(frame)
304
+ .filter((option) => option.forced.length === 0 && !isKeyboardActive(option))
305
+ .map((option) => ({ look: option.look, flag: option.selected })));
306
+ const selected = lookGapOf({ seen, flag: 'selected', what });
307
+ if (selected)
308
+ gaps.push(['option-selected', selected]);
309
+ return gaps;
310
+ };
311
+ const requirementGapsOf = (options) => {
312
+ var _a;
313
+ const { frames, id, control } = options;
314
+ const kind = (_a = KINDS[control.kind]) !== null && _a !== void 0 ? _a : {};
315
+ const own = control.part === null;
316
+ const instances = frames
317
+ .filter((frame) => frame.interaction === null)
318
+ .flatMap((frame) => frame.controls.filter((seen) => seen.id === id && seen.forced.length === 0));
319
+ const gaps = [];
320
+ for (const interaction of own ? requiredInteractionsOf(control) : []) {
321
+ const forcedGap = interactionGapOf({ frames, id, interaction });
322
+ const gap = forcedGap && interaction === 'focus-visible' && kind.virtualFocus
323
+ ? keyboardActiveRowGapOf({ instances, forcedGap })
324
+ : forcedGap;
325
+ if (gap)
326
+ gaps.push([interaction, gap]);
327
+ }
328
+ if (own && kind.selects) {
329
+ const selected = lookGapOf({
330
+ seen: instances.map((seen) => { var _a; return ({ look: seen.look, flag: (_a = seen.selected) !== null && _a !== void 0 ? _a : false }); }),
331
+ flag: 'selected',
332
+ what: 'it',
333
+ });
334
+ const forced = frames.flatMap((frame) => frame.controls
335
+ .filter((seen) => seen.id === id && seen.selected)
336
+ .flatMap((seen) => seen.forced.filter((force) => force.interaction === 'hover'))
337
+ .map((force) => ({ state: frame.state, differs: force.differs })));
338
+ const hovered = forcedGapOf({ forced, what: 'it selected', interaction: 'hover' });
339
+ if (selected)
340
+ gaps.push(['selected', selected]);
341
+ if (hovered)
342
+ gaps.push(['selected-hover', hovered]);
343
+ }
344
+ if (own && control.disabled) {
345
+ const disabled = lookGapOf({
346
+ seen: instances.map((seen) => { var _a; return ({ look: seen.look, flag: (_a = seen.disabled) !== null && _a !== void 0 ? _a : false }); }),
347
+ flag: 'disabled',
348
+ what: 'it',
349
+ marks: CONTROL_MARKS,
350
+ });
351
+ if (disabled)
352
+ gaps.push(['disabled', disabled]);
353
+ }
354
+ if (kind.surface)
355
+ gaps.push(...surfaceGapsOf(Object.assign(Object.assign({}, options), { surface: kind.surface, closed: kind.closed })));
356
+ if (own && kind.options && kind.surface)
357
+ gaps.push(...optionGapsOf({ frames, surfaceId: `${id}.${kind.surface}` }));
358
+ return gaps;
359
+ };
360
+ /**
361
+ * The gaps of one part, from its `controls` declaration, its state names and what each drawn frame showed.
362
+ * A part that is not `reviewed` (its files differ from its merged.json hash) has no reviewed evidence at all.
363
+ */
364
+ const completenessGapsOf = (options) => {
365
+ var _a;
366
+ const { part, states, frames, reviewed, grid, referenced = {}, inventory } = options;
367
+ const declared = (_a = (0, exports.declaredControlsOf)(options.controls)) !== null && _a !== void 0 ? _a : {};
368
+ const gaps = [];
369
+ if (!reviewed)
370
+ gaps.push({
371
+ code: 'PART-UNREVIEWED',
372
+ target: part,
373
+ detail: 'its files differ from the hash merged.json records for it, so no frame of it is reviewed - merge or accept it',
374
+ });
375
+ const seenIds = new Set(frames.flatMap((frame) => frame.controls.map((control) => control.id)));
376
+ for (const id of [...seenIds].filter((seen) => !(seen in declared)).sort())
377
+ gaps.push({
378
+ code: 'CONTROL-UNKNOWN',
379
+ target: `${part}.${id}`,
380
+ detail: `data-et-control="${id}" is not in controls`,
381
+ });
382
+ const surfaceIds = new Set(frames.flatMap((frame) => frame.surfaces.map((surface) => surface.id)));
383
+ for (const id of [...surfaceIds].sort()) {
384
+ const [control = '', surface = ''] = id.split('.');
385
+ if (!declared[control] || declared[control].surfaces[surface] === undefined)
386
+ gaps.push({
387
+ code: 'CONTROL-UNKNOWN',
388
+ target: `${part}.${control}`,
389
+ detail: `data-et-surface="${id}" names no surface its control declares`,
390
+ });
391
+ }
392
+ for (const [id, control] of Object.entries(declared)) {
393
+ if (!CHECKED_KINDS.includes(control.kind)) {
394
+ gaps.push({
395
+ code: 'CONTROL-KIND',
396
+ target: `${part}.${id}`,
397
+ detail: `kind "${control.kind}" is not checked yet - kinds are ${CHECKED_KINDS.join(', ')}`,
398
+ });
399
+ continue;
400
+ }
401
+ if (control.part === null && part.startsWith('pages/'))
402
+ gaps.push({
403
+ code: 'CONTROL-PART-MISSING',
404
+ target: `${part}.${id}`,
405
+ detail: "a page draws no interactions of its controls - name the part that draws them, e.g. part: 'components/disclosure'",
406
+ });
407
+ const used = control.part === null ? undefined : referenced[control.part];
408
+ if (typeof used === 'string')
409
+ gaps.push({ code: 'CONTROL-PART-INCOMPLETE', target: `${part}.${id}`, detail: `${control.part}: ${used}` });
410
+ else if (used && used.length > 0)
411
+ gaps.push({
412
+ code: 'CONTROL-PART-INCOMPLETE',
413
+ target: `${part}.${id}`,
414
+ detail: `${control.part} is not design complete: ${used.length} gap(s) - run design complete ${control.part}`,
415
+ });
416
+ const interactions = control.part === null && !part.startsWith('pages/') ? requiredInteractionsOf(control) : [];
417
+ const gridGap = interactions.length > 0 ? gridGapOf({ grid, states, interactions }) : null;
418
+ if (gridGap)
419
+ gaps.push({ code: 'CONTROL-GRID-MISSING', target: `${part}.${id}`, detail: gridGap });
420
+ if (!seenIds.has(id)) {
421
+ gaps.push({ code: 'CONTROL-UNDRAWN', target: `${part}.${id}`, detail: `no state draws data-et-control="${id}"` });
422
+ continue;
423
+ }
424
+ for (const [requirement, detail] of requirementGapsOf({ frames, id, control, states }))
425
+ gaps.push({ code: 'REQUIREMENT-MISSING', target: `${part}.${id}.${requirement}`, detail });
426
+ for (const interaction of interactions) {
427
+ const gap = stillGapOf({ frames, id, interaction });
428
+ if (gap)
429
+ gaps.push({ code: 'CONTROL-TRANSITION-MISSING', target: `${part}.${id}.${interaction}`, detail: gap });
430
+ }
431
+ }
432
+ return [
433
+ ...gaps,
434
+ ...discoveryGapsOf({ part, declared, frames }),
435
+ ...ownerGapsOf({ part, declared, frames, referenced }),
436
+ ...overrideGapsOf({ part, frames }),
437
+ ...inventoryGapsOf({ part, inventory }),
438
+ ];
439
+ };
440
+ exports.completenessGapsOf = completenessGapsOf;
441
+ const inventoryGapsOf = ({ part, inventory }) => {
442
+ const reason = inventory ? (0, inventory_approval_1.inventoryReasonOf)(inventory) : null;
443
+ return reason === null
444
+ ? []
445
+ : [{ code: 'INVENTORY-UNAPPROVED', target: part, detail: `${reason} - check and approve it in Studio` }];
446
+ };
447
+ const completenessGapLineOf = (gap) => `${gap.code} ${gap.target} - ${gap.detail}`;
448
+ exports.completenessGapLineOf = completenessGapLineOf;
449
+ const NO_MOTION = '*, *::before, *::after { transition: none !important; animation: none !important; }';
450
+ const PAD = 8;
451
+ const COLOUR_PROPERTIES = [
452
+ 'background-color',
453
+ 'color',
454
+ 'border-top-color',
455
+ 'border-right-color',
456
+ 'border-bottom-color',
457
+ 'border-left-color',
458
+ 'box-shadow',
459
+ ];
460
+ const COLOUR = COLOUR_PROPERTIES.indexOf('color');
461
+ const colourSnapshot = (at) => `((at) => {
462
+ const control = document.querySelector('[data-et-complete="' + at + '"]');
463
+ const motionOff = [...document.querySelectorAll('style')].find((style) => style.textContent === ${JSON.stringify(NO_MOTION)});
464
+ const elements = [control, ...control.querySelectorAll('*')];
465
+ const colours = elements.map((element) => {
466
+ const style = getComputedStyle(element);
467
+ return ${JSON.stringify(COLOUR_PROPERTIES)}.map((name) => {
468
+ const side = name.match(/^border-(\\w+)-color$/);
469
+ return side && parseFloat(style.getPropertyValue('border-' + side[1] + '-width')) === 0 ? '' : style.getPropertyValue(name);
470
+ });
471
+ });
472
+ if (motionOff) motionOff.disabled = true;
473
+ const transitions = elements.map((element) => {
474
+ const style = getComputedStyle(element);
475
+ return {
476
+ properties: style.transitionProperty.split(',').map((name) => name.trim()),
477
+ durations: style.transitionDuration.split(',').map((duration) => parseFloat(duration)),
478
+ };
479
+ });
480
+ if (motionOff) motionOff.disabled = false;
481
+ const parents = elements.map((element) => elements.indexOf(element.parentElement));
482
+ const names = elements.map((element) => element.tagName.toLowerCase() + (element.classList[0] ? '.' + element.classList[0] : ''));
483
+ return { colours, transitions, parents, names };
484
+ })(${JSON.stringify(at)})`;
485
+ const coversOf = (property) => {
486
+ if (property === 'background-color')
487
+ return ['all', 'background', property];
488
+ if (property.startsWith('border-'))
489
+ return ['all', 'border', 'border-color', property.replace(/-color$/, ''), property];
490
+ return ['all', property];
491
+ };
492
+ const stillChangesOf = (rest, forced) => forced.names.flatMap((name, element) => {
493
+ var _a;
494
+ const { properties, durations } = (_a = forced.transitions[element]) !== null && _a !== void 0 ? _a : { properties: [], durations: [] };
495
+ const still = COLOUR_PROPERTIES.filter((property, at) => {
496
+ var _a, _b, _c, _d, _e;
497
+ const [before, after] = [(_a = rest.colours[element]) !== null && _a !== void 0 ? _a : [], (_b = forced.colours[element]) !== null && _b !== void 0 ? _b : []];
498
+ if (before[at] === after[at])
499
+ return false;
500
+ const parent = (_c = forced.parents[element]) !== null && _c !== void 0 ? _c : -1;
501
+ const inherited = parent >= 0 ? [(_d = rest.colours[parent]) === null || _d === void 0 ? void 0 : _d[at], (_e = forced.colours[parent]) === null || _e === void 0 ? void 0 : _e[at]] : [];
502
+ if (property !== 'color' && before[at] === before[COLOUR] && after[at] === after[COLOUR])
503
+ return false;
504
+ if (property === 'color' && before[at] === inherited[0] && after[at] === inherited[1])
505
+ return false;
506
+ return !properties.some((covered, index) => { var _a; return coversOf(property).includes(covered) && ((_a = durations[index % durations.length]) !== null && _a !== void 0 ? _a : 0) > 0; });
507
+ });
508
+ return still.length > 0 ? [`${still.join(', ')} of ${name}`] : [];
509
+ });
510
+ const INTERACTIVE_ROLES = [
511
+ 'button',
512
+ 'checkbox',
513
+ 'combobox',
514
+ 'link',
515
+ 'menuitem',
516
+ 'menuitemcheckbox',
517
+ 'menuitemradio',
518
+ 'option',
519
+ 'radio',
520
+ 'scrollbar',
521
+ 'searchbox',
522
+ 'slider',
523
+ 'spinbutton',
524
+ 'switch',
525
+ 'tab',
526
+ 'textbox',
527
+ 'treeitem',
528
+ ];
529
+ const SDK_CONTROLS = [
530
+ '[et-button]',
531
+ '[et-icon-button]',
532
+ '[et-text-button]',
533
+ '[et-fab]',
534
+ '[et-window-control-button]',
535
+ '[et-overlay-close]',
536
+ 'et-accordion',
537
+ 'et-cascader',
538
+ 'et-checkbox',
539
+ 'et-chip',
540
+ 'et-color-input',
541
+ 'et-counter',
542
+ 'et-date-input',
543
+ 'et-date-range-input',
544
+ 'et-date-time-input',
545
+ 'et-duration-input',
546
+ 'et-form-field',
547
+ 'et-input',
548
+ 'et-menu-checkbox-item',
549
+ 'et-menu-radio-item',
550
+ 'et-number-input',
551
+ 'et-otp-input',
552
+ 'et-password-input',
553
+ 'et-phone-input',
554
+ 'et-radio',
555
+ 'et-range-slider',
556
+ 'et-rating',
557
+ 'et-segmented-button',
558
+ 'et-select',
559
+ 'et-select-option',
560
+ 'et-slider',
561
+ 'et-split-button',
562
+ 'et-switch',
563
+ 'et-tab',
564
+ 'et-tag-input',
565
+ 'et-textarea',
566
+ 'et-time-input',
567
+ 'et-toggletip',
568
+ ];
569
+ const LIKELY_CONTROLS = [
570
+ ...SDK_CONTROLS,
571
+ 'button',
572
+ 'a[href]',
573
+ 'input:not([type="hidden"])',
574
+ 'select',
575
+ 'textarea',
576
+ 'summary',
577
+ '[tabindex]',
578
+ ...INTERACTIVE_ROLES.map((role) => `[role="${role}"]`),
579
+ ];
580
+ const LOOK_PROPERTIES = [...COLOUR_PROPERTIES, 'opacity', 'box-shadow', 'font-weight', 'text-decoration-line'];
581
+ const OPTION_SELECTOR = '[role="option"], [role^="menuitem"], [data-et-option]';
582
+ const discoverControls = `((root) => {
583
+ const LIKELY = ${JSON.stringify(LIKELY_CONTROLS)};
584
+ const likely = LIKELY.join(', ');
585
+ const sdk = ${JSON.stringify(SDK_CONTROLS.join(', '))};
586
+ const rendered = (element) => element.getClientRects().length > 0;
587
+ const HOVER = /(?<!\\\\):hover(?![\\w-])/g;
588
+ const FORCED_HOVER = /:is\\(:hover,\\s*\\[data-et-force~="?hover"?\\]\\)/g;
589
+ const hoveredOf = (written) => {
590
+ const selector = written.replace(FORCED_HOVER, ':hover');
591
+ const match = new RegExp(HOVER.source).exec(selector);
592
+ if (!match) return null;
593
+ let depth = 0;
594
+ let end = selector.length;
595
+ for (let at = 0; at < selector.length; at++) {
596
+ const char = selector[at];
597
+ if (char === '\\\\') at++;
598
+ else if (char === '(' || char === '[') depth++;
599
+ else if (char === ')' || char === ']') depth--;
600
+ else if (at > match.index && depth === 0 && /[\\s>+~]/.test(char)) {
601
+ end = at;
602
+ break;
603
+ }
604
+ }
605
+ return selector.slice(0, end).replace(HOVER, '').trim() || null;
606
+ };
607
+ const hovered = new Set();
608
+ const walk = (rules, parent) => {
609
+ for (const rule of rules) {
610
+ if (rule instanceof CSSStyleRule) {
611
+ const own = splitTop(rule.selectorText).map((selector) =>
612
+ nested(selector, parent),
613
+ );
614
+ for (const selector of own) {
615
+ const target = hoveredOf(selector);
616
+ if (target === null) continue;
617
+ try {
618
+ for (const element of root.querySelectorAll(target)) hovered.add(element);
619
+ } catch {}
620
+ }
621
+ if (rule.cssRules && rule.cssRules.length > 0) walk(rule.cssRules, own.join(', '));
622
+ } else if (rule.cssRules) walk(rule.cssRules, parent);
623
+ }
624
+ };
625
+ for (const sheet of document.styleSheets) {
626
+ try {
627
+ walk(sheet.cssRules, null);
628
+ } catch {}
629
+ }
630
+ const markerOf = (at, element) =>
631
+ at.getAttribute('data-et-control') ?? (element.matches(${JSON.stringify(OPTION_SELECTOR)}) ? at.getAttribute('data-et-surface')?.split('.')[0] : null) ?? null;
632
+ const withinOf = (element) => {
633
+ const ids = [];
634
+ for (let at = element; at && at !== root; at = at.parentElement) {
635
+ const id = markerOf(at, element);
636
+ if (id !== null) ids.push(id);
637
+ }
638
+ return ids;
639
+ };
640
+ const markedOf = (element) => {
641
+ if (element.hasAttribute('data-et-control')) return element.getAttribute('data-et-control');
642
+ for (let at = element.parentElement; at && at !== root; at = at.parentElement) {
643
+ if (at.matches(likely)) return null;
644
+ const id = markerOf(at, element);
645
+ if (id !== null) return id;
646
+ }
647
+ return null;
648
+ };
649
+ const found = [];
650
+ for (const element of root.querySelectorAll('*')) {
651
+ if (!rendered(element)) continue;
652
+ const what = LIKELY.find((selector) => element.matches(selector));
653
+ if (what) {
654
+ const inSdk = element.parentElement.closest(sdk);
655
+ if (inSdk !== null && root.contains(inSdk)) continue;
656
+ found.push({ kind: 'control', what: what.startsWith('[') ? element.tagName.toLowerCase() + what : what, path: pathOf(element), marked: markedOf(element), within: withinOf(element), owner: ownerOf(element)?.key ?? null, box: frameBoxOf(element) });
657
+ continue;
658
+ }
659
+ const cursor = getComputedStyle(element).cursor;
660
+ const pointer = cursor === 'pointer' && getComputedStyle(element.parentElement).cursor !== 'pointer';
661
+ if (!pointer && !hovered.has(element)) continue;
662
+ if (element.closest('[data-et-control], ' + likely) !== null) continue;
663
+ const reason = [pointer ? 'cursor: pointer' : '', hovered.has(element) ? ':hover rule' : ''].filter(Boolean).join(' and ');
664
+ found.push({ kind: 'unclassified', what: nameOf(element) + ' with ' + reason, path: pathOf(element), marked: null, within: [], owner: ownerOf(element)?.key ?? null, box: frameBoxOf(element) });
665
+ }
666
+ return found;
667
+ })`;
668
+ const ROOT_LAYOUT = [
669
+ '^margin',
670
+ '^inset',
671
+ '^(top|right|bottom|left)$',
672
+ '^(min-|max-)?(width|height|inline-size|block-size)$',
673
+ '^position$',
674
+ '^z-index$',
675
+ '^flex(-grow|-shrink|-basis)?$',
676
+ '^grid-(area|row|column)',
677
+ '^(align|justify|place)-self$',
678
+ '^order$',
679
+ '^(transform|translate|rotate|scale)$',
680
+ ];
681
+ const findOverrides = `((ownCss) => {
682
+ const LAYOUT = new RegExp(${JSON.stringify(ROOT_LAYOUT.join('|'))});
683
+ const USER_ACTION = /(?<!\\\\):(hover|focus-visible|focus-within|focus|active)(?![\\w-])/g;
684
+ const PSEUDO_ELEMENT = /::?(before|after|marker|placeholder|selection|backdrop|file-selector-button|first-line|first-letter)(?![\\w-])/g;
685
+ const declaredByHost = (element) => {
686
+ for (let at = element; at && at !== root.parentElement; at = at.parentElement)
687
+ if (at.hasAttribute('data-et-control') && ownerOf(at) === null) return true;
688
+ return false;
689
+ };
690
+ const overrides = [];
691
+ const seen = new Set();
692
+ const check = (selector, style) => {
693
+ const properties = [...new Set(style.cssText.split(';').map((declaration) => declaration.split(':')[0].trim()).filter(Boolean))];
694
+ if (properties.length === 0) return;
695
+ let matched = [];
696
+ try {
697
+ matched = [...root.querySelectorAll(selector.replace(PSEUDO_ELEMENT, '').replace(USER_ACTION, ':where(*)'))];
698
+ } catch {
699
+ return;
700
+ }
701
+ for (const element of matched) {
702
+ const owner = ownerOf(element);
703
+ if (owner === null || declaredByHost(element)) continue;
704
+ const look = owner.at === element ? properties.filter((property) => !LAYOUT.test(property)) : properties;
705
+ const key = selector + ' ' + pathOf(element);
706
+ if (look.length === 0 || seen.has(key)) continue;
707
+ seen.add(key);
708
+ overrides.push({ owner: owner.key, selector, path: pathOf(element), properties: look });
709
+ }
710
+ };
711
+ const walk = (rules, parent) => {
712
+ for (const rule of rules) {
713
+ if (rule instanceof CSSStyleRule) {
714
+ const own = splitTop(rule.selectorText).map((selector) => nested(selector, parent));
715
+ for (const selector of own) check(selector, rule.style);
716
+ if (rule.cssRules && rule.cssRules.length > 0) walk(rule.cssRules, own.join(', '));
717
+ } else if (parent !== null && rule.constructor.name === 'CSSNestedDeclarations') check(parent, rule.style);
718
+ else if (rule.cssRules) walk(rule.cssRules, parent);
719
+ }
720
+ };
721
+ for (const text of ownCss) {
722
+ const sheet = new CSSStyleSheet();
723
+ try {
724
+ sheet.replaceSync(text);
725
+ } catch {
726
+ continue;
727
+ }
728
+ walk(sheet.cssRules, null);
729
+ }
730
+ return overrides;
731
+ })`;
732
+ /** A control root and every `data-et-control-part` whose nearest `data-et-control` is that root, in the page. */
733
+ const controlPartsOf = `((control) => [
734
+ control,
735
+ ...[...control.querySelectorAll('[data-et-control-part]')].filter((part) => part.parentElement.closest('[data-et-control]') === control),
736
+ ])`;
737
+ const seeFrame = (options) => `(() => {
738
+ const root = document.getElementById('root');
739
+ const refused = root.innerText.trim();
740
+ if (refused.startsWith('design-explore:')) return { refused: refused.split('\\n')[0] };
741
+ const ORIGIN = ${options.clip} ? root.getBoundingClientRect() : { left: -scrollX, top: -scrollY };
742
+ const frameBoxOf = (element) => {
743
+ const box = element.getBoundingClientRect();
744
+ return box.width > 0 && box.height > 0
745
+ ? { x: Math.round(box.left - ORIGIN.left), y: Math.round(box.top - ORIGIN.top), width: Math.round(box.width), height: Math.round(box.height) }
746
+ : null;
747
+ };
748
+ const OWN = ${JSON.stringify(options.part)};
749
+ const tokensOf = (element, name) => (element.getAttribute(name) ?? '').split(' ').filter(Boolean);
750
+ const ownerOf = (element) => {
751
+ const slotted = tokensOf(element, 'data-et-slot');
752
+ for (let at = element; at; at = at.parentElement)
753
+ for (const key of tokensOf(at, 'data-et-part')) {
754
+ const index = slotted.indexOf(key);
755
+ if (index >= 0) slotted.splice(index, 1);
756
+ else return key === OWN ? null : { key, at };
757
+ }
758
+ return null;
759
+ };
760
+ const nameOf = (element) => {
761
+ const cls = [...element.classList].find((name) => /^[a-z][\\w-]*$/i.test(name));
762
+ return element.tagName.toLowerCase() + (cls ? '.' + cls : '');
763
+ };
764
+ const pathOf = (element) => {
765
+ const names = [];
766
+ for (let at = element; at && at !== root; at = at.parentElement) names.unshift(nameOf(at));
767
+ return (names.length > 4 ? '... > ' : '') + names.slice(-4).join(' > ');
768
+ };
769
+ const splitTop = (selector) => {
770
+ const parts = [];
771
+ let depth = 0;
772
+ let from = 0;
773
+ for (let at = 0; at < selector.length; at++) {
774
+ const char = selector[at];
775
+ if (char === '\\\\') at++;
776
+ else if (char === '(' || char === '[') depth++;
777
+ else if (char === ')' || char === ']') depth--;
778
+ else if (char === ',' && depth === 0) {
779
+ parts.push(selector.slice(from, at).trim());
780
+ from = at + 1;
781
+ }
782
+ }
783
+ parts.push(selector.slice(from).trim());
784
+ return parts.filter(Boolean);
785
+ };
786
+ const nested = (selector, parent) =>
787
+ parent === null ? selector : selector.includes('&') ? selector.replaceAll('&', ':is(' + parent + ')') : ':is(' + parent + ') ' + selector;
788
+ const shown = (element) => {
789
+ const box = element.getBoundingClientRect();
790
+ let { left, top, right, bottom } = box;
791
+ if (box.width <= 0 || box.height <= 0) return false;
792
+ if (['hidden', 'collapse'].includes(getComputedStyle(element).visibility)) return false;
793
+ for (let at = element; at; at = at.parentElement) {
794
+ const style = getComputedStyle(at);
795
+ if (Number(style.opacity) === 0) return false;
796
+ if (at === element) continue;
797
+ const clip = at.getBoundingClientRect();
798
+ if (style.overflowX !== 'visible') [left, right] = [Math.max(left, clip.left), Math.min(right, clip.right)];
799
+ if (style.overflowY !== 'visible') [top, bottom] = [Math.max(top, clip.top), Math.min(bottom, clip.bottom)];
800
+ if (right <= left || bottom <= top) return false;
801
+ }
802
+ return element.innerText.trim() !== '' || !!element.querySelector('img, svg, canvas, video, iframe, input, select, textarea');
803
+ };
804
+ const LOOK = ${JSON.stringify(LOOK_PROPERTIES)};
805
+ const lookOf = (element) => {
806
+ const own = LOOK.map((name) => getComputedStyle(element).getPropertyValue(name));
807
+ const inside = [...element.querySelectorAll('*')].map((child) => {
808
+ const style = getComputedStyle(child);
809
+ return LOOK.map((name) => style.getPropertyValue(name)).join(' ');
810
+ });
811
+ return JSON.stringify([own, [...new Set(inside)].sort()]);
812
+ };
813
+ const named = new Set([...root.querySelectorAll('[aria-activedescendant]')].filter((element) => ownerOf(element) === null).map((element) => element.getAttribute('aria-activedescendant')));
814
+ const isSelected = (element) =>
815
+ ['aria-selected', 'aria-checked', 'aria-pressed'].some((name) => element.getAttribute(name) === 'true') ||
816
+ (element.hasAttribute('aria-current') && element.getAttribute('aria-current') !== 'false');
817
+ const isDisabled = (element) =>
818
+ element.matches(':disabled') || element.getAttribute('aria-disabled') === 'true' || tokensOf(element, 'data-et-force').includes('disabled');
819
+ const isKeyboard = (element) => element.getAttribute('data-active-source') === 'keyboard';
820
+ let next = 0;
821
+ const tagged = (element) => {
822
+ const at = next++;
823
+ element.setAttribute('data-et-complete', String(at));
824
+ const box = element.getBoundingClientRect();
825
+ const x = Math.max(0, box.x + scrollX - ${PAD});
826
+ const y = Math.max(0, box.y + scrollY - ${PAD});
827
+ return {
828
+ at,
829
+ forced: tokensOf(element, 'data-et-force'),
830
+ box: box.width > 0 && box.height > 0 ? { x, y, width: box.width + ${PAD * 2}, height: box.height + ${PAD * 2} } : null,
831
+ selected: isSelected(element),
832
+ look: lookOf(element),
833
+ };
834
+ };
835
+ const controls = [...root.querySelectorAll('[data-et-control]')].filter((element) => ownerOf(element) === null).map((element) => {
836
+ const parts = ${controlPartsOf}(element);
837
+ const forced = new Set(parts.flatMap((part) => tokensOf(part, 'data-et-force')));
838
+ for (const part of parts) if (forced.size > 0) part.setAttribute('data-et-force', [...forced].join(' '));
839
+ return {
840
+ id: element.getAttribute('data-et-control'),
841
+ disabled: parts.some(isDisabled),
842
+ keyboard: parts.some(isKeyboard),
843
+ frameBox: frameBoxOf(element),
844
+ ...tagged(element),
845
+ };
846
+ });
847
+ const surfaces = [...root.querySelectorAll('[data-et-surface]')].filter((element) => ownerOf(element) === null).map((element) => ({
848
+ id: element.getAttribute('data-et-surface'),
849
+ shown: shown(element),
850
+ options: [...element.querySelectorAll(${JSON.stringify(OPTION_SELECTOR)})].filter((option) => ownerOf(option) === null && shown(option)).map((option) => ({ ...tagged(option), named: option.id !== '' && named.has(option.id), keyboard: isKeyboard(option) })),
851
+ }));
852
+ const discover = ${options.discover};
853
+ return {
854
+ controls,
855
+ surfaces,
856
+ found: discover ? ${discoverControls}(root) : [],
857
+ overrides: discover ? ${findOverrides}(${JSON.stringify(options.ownCss)}) : [],
858
+ };
859
+ })()`;
860
+ const forceOn = ({ at, interaction, on, }) => `((at, interaction, on) => {
861
+ const found = document.querySelector('[data-et-complete="' + at + '"]');
862
+ for (const element of found.hasAttribute('data-et-control') ? ${controlPartsOf}(found) : [found]) {
863
+ const tokens = new Set((element.getAttribute('data-et-force') ?? '').split(' ').filter(Boolean));
864
+ if (on) tokens.add(interaction);
865
+ else tokens.delete(interaction);
866
+ if (tokens.size > 0) element.setAttribute('data-et-force', [...tokens].join(' '));
867
+ else element.removeAttribute('data-et-force');
868
+ }
869
+ })(${JSON.stringify(at)}, ${JSON.stringify(interaction)}, ${JSON.stringify(on)})`;
870
+ const FORCEABLE = new Set(['hover', 'focus-visible', 'active']);
871
+ const seeFrames = (options) => __awaiter(void 0, void 0, void 0, function* () {
872
+ const { browser, base, frames, part, ownCss } = options;
873
+ const context = yield browser.newContext();
874
+ const seen = [];
875
+ const refused = [];
876
+ try {
877
+ const page = yield context.newPage();
878
+ for (const frame of frames) {
879
+ yield page.setViewportSize((0, shot_1.viewportOf)(frame.size));
880
+ yield (0, thumb_1.openFrame)(page, `${base}/frame.html?${frame.search}`);
881
+ yield page.addStyleTag({ content: NO_MOTION });
882
+ yield page.evaluate(thumb_1.settled);
883
+ const found = (yield page.evaluate(seeFrame({ discover: frame.interaction === null, part, ownCss, clip: frame.clip })));
884
+ if ('refused' in found) {
885
+ refused.push(`${frame.state}: ${found.refused}`);
886
+ continue;
887
+ }
888
+ const forcedOf = (element) => __awaiter(void 0, void 0, void 0, function* () {
889
+ const forced = [];
890
+ for (const interaction of element.forced.filter((name) => FORCEABLE.has(name))) {
891
+ if (!element.box) {
892
+ forced.push({ interaction, differs: false });
893
+ continue;
894
+ }
895
+ const shot = () => { var _a; return page.screenshot({ type: 'png', fullPage: true, clip: (_a = element.box) !== null && _a !== void 0 ? _a : undefined, animations: 'disabled' }); };
896
+ const drawn = yield shot();
897
+ const drawnColours = (yield page.evaluate(colourSnapshot(element.at)));
898
+ yield page.evaluate(forceOn({ at: element.at, interaction, on: false }));
899
+ yield page.evaluate(thumb_1.settled);
900
+ const rest = yield shot();
901
+ const restColours = (yield page.evaluate(colourSnapshot(element.at)));
902
+ yield page.evaluate(forceOn({ at: element.at, interaction, on: true }));
903
+ forced.push({
904
+ interaction,
905
+ differs: !drawn.equals(rest),
906
+ still: stillChangesOf(restColours, drawnColours),
907
+ });
908
+ }
909
+ return forced;
910
+ });
911
+ const controls = [];
912
+ const surfaces = [];
913
+ for (const control of found.controls)
914
+ controls.push(Object.assign(Object.assign({ id: control.id, forced: yield forcedOf(control), selected: control.selected, disabled: control.disabled, look: control.look }, (control.keyboard ? { keyboard: true } : {})), { box: control.frameBox }));
915
+ for (const surface of found.surfaces) {
916
+ const options = [];
917
+ for (const option of surface.options)
918
+ options.push(Object.assign(Object.assign({ selected: option.selected, look: option.look, forced: yield forcedOf(option) }, (option.named ? { named: true } : {})), (option.keyboard ? { keyboard: true } : {})));
919
+ surfaces.push({ id: surface.id, shown: surface.shown, options });
920
+ }
921
+ seen.push({
922
+ state: frame.state,
923
+ interaction: frame.interaction,
924
+ controls,
925
+ surfaces,
926
+ found: found.found,
927
+ overrides: found.overrides,
928
+ });
929
+ }
930
+ }
931
+ finally {
932
+ yield context.close();
933
+ }
934
+ return { seen, refused };
935
+ });
936
+ /**
937
+ * Draws every state of one part of the product, at rest and, unless `restOnly`, in each interaction it declares,
938
+ * once at its first preset or width, and answers what each frame showed, or why its module did not load as a string.
939
+ */
940
+ const seePart = (options) => __awaiter(void 0, void 0, void 0, function* () {
941
+ var _a, _b, _c, _d, _e;
942
+ const { product, part, system, base, load, draw, restOnly = false, sketch = null } = options;
943
+ const key = (0, resolve_product_1.partKeyOf)(part);
944
+ const loaded = yield load((0, system_modules_1.productModuleIdOf)({ file: part.file, product: product.name, sketch }))
945
+ .then((module) => ({ module: module }))
946
+ .catch((error) => ({ error: error instanceof Error ? error.message : String(error) }));
947
+ if ('error' in loaded)
948
+ return loaded.error;
949
+ const definition = loaded.module.default;
950
+ const states = isRecord(definition === null || definition === void 0 ? void 0 : definition.states) ? Object.keys(definition.states) : [];
951
+ const interactions = Array.isArray(definition === null || definition === void 0 ? void 0 : definition.interactions)
952
+ ? definition.interactions.filter((name) => force_interactions_1.INTERACTIONS.some((known) => known === name))
953
+ : [];
954
+ const widths = Array.isArray(definition === null || definition === void 0 ? void 0 : definition.widths)
955
+ ? definition.widths.filter((width) => typeof width === 'number')
956
+ : [];
957
+ const presets = Object.keys((_b = (_a = system.drawnOf(product.name, null)) === null || _a === void 0 ? void 0 : _a.presets) !== null && _b !== void 0 ? _b : {});
958
+ const preset = part.layer === 'pages' ? ((_c = presets[0]) !== null && _c !== void 0 ? _c : null) : null;
959
+ const width = preset === null ? ((_d = widths[0]) !== null && _d !== void 0 ? _d : null) : null;
960
+ const frames = [];
961
+ for (const state of states)
962
+ for (const interaction of [null, ...(restOnly ? [] : interactions)]) {
963
+ const frame = (0, shot_1.partFrameOf)({
964
+ system,
965
+ product: product.name,
966
+ part: key,
967
+ state,
968
+ preset,
969
+ width,
970
+ sketch,
971
+ interaction,
972
+ });
973
+ if (!(frame instanceof Error))
974
+ frames.push({
975
+ state,
976
+ interaction,
977
+ search: frame.search.toString(),
978
+ size: (_e = frame.size) !== null && _e !== void 0 ? _e : null,
979
+ clip: preset === null,
980
+ });
981
+ }
982
+ const dir = (0, path_1.dirname)(part.file);
983
+ const ownCss = (0, fs_1.readdirSync)(dir)
984
+ .filter((file) => file.endsWith('.css'))
985
+ .sort()
986
+ .map((file) => (0, fs_1.readFileSync)((0, path_1.join)(dir, file), 'utf8'));
987
+ const { seen, refused } = yield draw((browser) => seeFrames({ browser, base, frames, part: key, ownCss }));
988
+ const owner = (0, inventory_approval_1.partOwnerOf)({ product, part });
989
+ return {
990
+ definition,
991
+ states,
992
+ seen,
993
+ refused,
994
+ addresses: states.map((state) => ({ state, preset, width })),
995
+ owner,
996
+ hash: (0, baseline_1.partHashOf)({ product: owner, dir }),
997
+ };
998
+ });
999
+ exports.seePart = seePart;
1000
+ /** The control ids a page draws at rest, the set its inventory approval holds. */
1001
+ const inventoryIdsOf = (frames) => [
1002
+ ...new Set(frames.filter((frame) => frame.interaction === null).flatMap((frame) => frame.controls.map(({ id }) => id))),
1003
+ ].sort();
1004
+ exports.inventoryIdsOf = inventoryIdsOf;
1005
+ /**
1006
+ * Draws every state of one part, at rest and in each interaction it declares, once at its first preset or width,
1007
+ * and answers the gaps of its `controls` declaration, or why it could not draw. A part a control names in `part`,
1008
+ * and an embedded part whose `data-et-part` root draws a control, is checked the same way, and its gaps fail it.
1009
+ * A page fails until the user approves its control inventory in Studio. An exception the user approved in Studio
1010
+ * drops the gap it names until the part changes; a pending one still fails. With `sketch`, every part is drawn as
1011
+ * that variant draws it, and a part the variant changes is not merged yet, so it never fails as unreviewed.
1012
+ */
1013
+ const completenessOf = (options) => __awaiter(void 0, void 0, void 0, function* () {
1014
+ var _a, _b, _c, _d;
1015
+ const { target, config, product, part, sketch = null } = options;
1016
+ const resolveChromium = (_a = options.chromiumOf) !== null && _a !== void 0 ? _a : browser_1.chromiumOf;
1017
+ const system = (0, system_modules_1.createSystemModules)({ target, config });
1018
+ const parts = (_c = (_b = (sketch ? system.drawnOf(product.name, sketch) : product)) === null || _b === void 0 ? void 0 : _b.parts) !== null && _c !== void 0 ? _c : [];
1019
+ if (!parts.some((candidate) => (0, resolve_product_1.partKeyOf)(candidate) === part))
1020
+ return {
1021
+ problem: sketch
1022
+ ? `variant "${sketch.variant}" of the sketch on ${sketch.target} in product "${product.name}" has no part "${part}"`
1023
+ : `product "${product.name}" has no part "${part}"`,
1024
+ };
1025
+ if (!(yield resolveChromium(target)))
1026
+ return { unavailable: 'neither the checkout nor this package resolves playwright or playwright-core' };
1027
+ const queue = (0, thumb_1.createDrawQueue)({ target, chromiumOf: resolveChromium });
1028
+ const server = yield (0, serve_1.createDesignServer)({ target, config, listen: true, port: 0 });
1029
+ try {
1030
+ yield server.listen();
1031
+ const { port } = (_d = server.httpServer) === null || _d === void 0 ? void 0 : _d.address();
1032
+ const checked = new Map();
1033
+ const exceptions = [];
1034
+ const gapsOfPart = (key, chain) => __awaiter(void 0, void 0, void 0, function* () {
1035
+ const known = checked.get(key);
1036
+ if (known !== undefined && !chain.includes(key))
1037
+ return known;
1038
+ const gaps = yield freshGapsOfPart(key, chain);
1039
+ checked.set(key, gaps);
1040
+ return gaps;
1041
+ });
1042
+ const freshGapsOfPart = (key, chain) => __awaiter(void 0, void 0, void 0, function* () {
1043
+ var _a, _b, _c;
1044
+ const resolved = parts.find((candidate) => (0, resolve_product_1.partKeyOf)(candidate) === key);
1045
+ if (!resolved)
1046
+ return `product "${product.name}" has no part "${key}"`;
1047
+ if (chain.includes(key))
1048
+ return `its controls name each other in a cycle: ${[...chain, key].join(' > ')}`;
1049
+ const sight = yield (0, exports.seePart)({
1050
+ product,
1051
+ part: resolved,
1052
+ system,
1053
+ base: `http://localhost:${port}`,
1054
+ load: (id) => server.ssrLoadModule(id),
1055
+ draw: (job) => queue.run(job),
1056
+ sketch,
1057
+ });
1058
+ if (typeof sight === 'string')
1059
+ return [{ code: 'RENDER', target: key, detail: (_a = sight.split('\n')[0]) !== null && _a !== void 0 ? _a : '' }];
1060
+ const { definition, states, seen, refused, owner, hash } = sight;
1061
+ const sketched = ((_b = product.parts.find((candidate) => (0, resolve_product_1.partKeyOf)(candidate) === key)) === null || _b === void 0 ? void 0 : _b.file) !== resolved.file;
1062
+ const reviewed = sketched || (0, merged_parts_1.readMerged)(owner.dir)[key] === hash;
1063
+ const referenced = {};
1064
+ const used = [
1065
+ ...Object.values((_c = (0, exports.declaredControlsOf)(definition === null || definition === void 0 ? void 0 : definition.controls)) !== null && _c !== void 0 ? _c : {}).map((control) => control.part),
1066
+ ...ownersOf(seen),
1067
+ ];
1068
+ for (const other of used)
1069
+ if (other !== null && !(other in referenced))
1070
+ referenced[other] = yield gapsOfPart(other, [...chain, key]);
1071
+ const excepted = (0, exceptions_1.withExceptions)({
1072
+ part: key,
1073
+ exceptions: (0, exceptions_1.readExceptions)(owner.dir),
1074
+ hash,
1075
+ gaps: (0, exports.completenessGapsOf)({
1076
+ part: key,
1077
+ controls: definition === null || definition === void 0 ? void 0 : definition.controls,
1078
+ states,
1079
+ frames: seen,
1080
+ reviewed,
1081
+ grid: definition === null || definition === void 0 ? void 0 : definition.grid,
1082
+ referenced,
1083
+ inventory: resolved.layer === 'pages'
1084
+ ? (0, inventory_approval_1.inventoryStateOf)({ approval: (0, inventory_approval_1.readInventory)(owner.dir)[key], ids: (0, exports.inventoryIdsOf)(seen), hash })
1085
+ : undefined,
1086
+ }),
1087
+ });
1088
+ exceptions.push(...excepted.listed);
1089
+ return [...refused.map((detail) => ({ code: 'RENDER', target: key, detail })), ...excepted.gaps];
1090
+ });
1091
+ const gaps = yield gapsOfPart(part, []);
1092
+ if (typeof gaps === 'string')
1093
+ return { problem: gaps };
1094
+ return exceptions.length > 0 ? { gaps, exceptions } : { gaps };
1095
+ }
1096
+ catch (error) {
1097
+ if (error instanceof thumb_1.ThumbUnavailableError)
1098
+ return { unavailable: error.message };
1099
+ throw error;
1100
+ }
1101
+ finally {
1102
+ yield Promise.all([queue.close(), server.close()]);
1103
+ }
1104
+ });
1105
+ exports.completenessOf = completenessOf;
1106
+ //# sourceMappingURL=complete.js.map