@ethlete/cli 3.0.0-next.25 → 3.0.0-next.26
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.
- package/CHANGELOG.md +89 -0
- package/design/define-call.ts +29 -3
- package/design/define-part.ts +15 -1
- package/design/logo-sheet.ts +52 -0
- package/design/motion-drive.ts +215 -0
- package/design/motion-runtime.ts +14 -2
- package/design/motion-tokens.ts +177 -0
- package/design/web/frame-fill.ts +4 -0
- package/design/web/frame-scheme.ts +44 -0
- package/design/web/frame.ts +122 -29
- package/package.json +1 -1
- package/src/lib/design/calls-tsconfig.d.ts +2 -0
- package/src/lib/design/calls-tsconfig.js +10 -3
- package/src/lib/design/calls-tsconfig.js.map +1 -1
- package/src/lib/design/check.d.ts +1 -0
- package/src/lib/design/check.js +62 -6
- package/src/lib/design/check.js.map +1 -1
- package/src/lib/design/contact-sheet.d.ts +9 -0
- package/src/lib/design/contact-sheet.js +38 -4
- package/src/lib/design/contact-sheet.js.map +1 -1
- package/src/lib/design/design-command.js +27 -8
- package/src/lib/design/design-command.js.map +1 -1
- package/src/lib/design/draw-ledger.d.ts +36 -0
- package/src/lib/design/draw-ledger.js +52 -0
- package/src/lib/design/draw-ledger.js.map +1 -0
- package/src/lib/design/mcp-command.d.ts +23 -2
- package/src/lib/design/mcp-command.js +105 -10
- package/src/lib/design/mcp-command.js.map +1 -1
- package/src/lib/design/motion-command.js +9 -15
- package/src/lib/design/motion-command.js.map +1 -1
- package/src/lib/design/paths.d.ts +14 -0
- package/src/lib/design/paths.js +50 -1
- package/src/lib/design/paths.js.map +1 -1
- package/src/lib/design/render-packages.d.ts +5 -0
- package/src/lib/design/render-packages.js +6 -1
- package/src/lib/design/render-packages.js.map +1 -1
- package/src/lib/design/render-worker.js +1 -0
- package/src/lib/design/render-worker.js.map +1 -1
- package/src/lib/design/serve.d.ts +2 -2
- package/src/lib/design/serve.js +158 -19
- package/src/lib/design/serve.js.map +1 -1
- package/src/lib/design/shot-command.d.ts +5 -2
- package/src/lib/design/shot-command.js +18 -16
- package/src/lib/design/shot-command.js.map +1 -1
- package/src/lib/design/shot-store.d.ts +24 -0
- package/src/lib/design/shot-store.js +120 -0
- package/src/lib/design/shot-store.js.map +1 -0
- package/src/lib/design/shot.d.ts +21 -1
- package/src/lib/design/shot.js +118 -31
- package/src/lib/design/shot.js.map +1 -1
- package/src/lib/design/sketch-command.js +121 -37
- package/src/lib/design/sketch-command.js.map +1 -1
- package/src/lib/design/ssr-shims.d.ts +2 -0
- package/src/lib/design/ssr-shims.js +12 -1
- package/src/lib/design/ssr-shims.js.map +1 -1
- package/src/lib/design/studio-api.d.ts +12 -0
- package/src/lib/design/studio-api.js +68 -2
- package/src/lib/design/studio-api.js.map +1 -1
- package/src/lib/design/system/check-system.d.ts +6 -2
- package/src/lib/design/system/check-system.js +102 -20
- package/src/lib/design/system/check-system.js.map +1 -1
- package/src/lib/design/system/colour.d.ts +4 -1
- package/src/lib/design/system/colour.js +54 -2
- package/src/lib/design/system/colour.js.map +1 -1
- package/src/lib/design/system/complete-command.js +6 -2
- package/src/lib/design/system/complete-command.js.map +1 -1
- package/src/lib/design/system/complete.d.ts +67 -2
- package/src/lib/design/system/complete.js +227 -53
- package/src/lib/design/system/complete.js.map +1 -1
- package/src/lib/design/system/contrast-check.d.ts +6 -1
- package/src/lib/design/system/contrast-check.js +167 -12
- package/src/lib/design/system/contrast-check.js.map +1 -1
- package/src/lib/design/system/drawn-open-points.d.ts +16 -0
- package/src/lib/design/system/drawn-open-points.js +43 -0
- package/src/lib/design/system/drawn-open-points.js.map +1 -0
- package/src/lib/design/system/list-system.d.ts +4 -1
- package/src/lib/design/system/list-system.js +2 -1
- package/src/lib/design/system/list-system.js.map +1 -1
- package/src/lib/design/system/open-points.d.ts +101 -0
- package/src/lib/design/system/open-points.js +156 -0
- package/src/lib/design/system/open-points.js.map +1 -0
- package/src/lib/design/system/part-ready.d.ts +52 -0
- package/src/lib/design/system/part-ready.js +101 -0
- package/src/lib/design/system/part-ready.js.map +1 -0
- package/src/lib/design/system/read-open-points.d.ts +27 -0
- package/src/lib/design/system/read-open-points.js +81 -0
- package/src/lib/design/system/read-open-points.js.map +1 -0
- package/src/lib/design/system/ready-command.d.ts +7 -0
- package/src/lib/design/system/ready-command.js +65 -0
- package/src/lib/design/system/ready-command.js.map +1 -0
- package/src/lib/design/system/render-check.d.ts +2 -0
- package/src/lib/design/system/render-check.js +197 -31
- package/src/lib/design/system/render-check.js.map +1 -1
- package/src/lib/design/system/resolve-product.d.ts +2 -1
- package/src/lib/design/system/resolve-product.js +20 -3
- package/src/lib/design/system/resolve-product.js.map +1 -1
- package/src/lib/design/system/rules/implements.d.ts +7 -0
- package/src/lib/design/system/rules/implements.js +43 -0
- package/src/lib/design/system/rules/implements.js.map +1 -0
- package/src/lib/design/system/rules/motion.d.ts +2 -0
- package/src/lib/design/system/rules/motion.js +26 -1
- package/src/lib/design/system/rules/motion.js.map +1 -1
- package/src/lib/design/system/rules/option-values.d.ts +15 -0
- package/src/lib/design/system/rules/option-values.js +145 -0
- package/src/lib/design/system/rules/option-values.js.map +1 -0
- package/src/lib/design/system/rules/stale-replace.js +41 -3
- package/src/lib/design/system/rules/stale-replace.js.map +1 -1
- package/src/lib/design/system/sketch/baseline.d.ts +11 -2
- package/src/lib/design/system/sketch/baseline.js +4 -2
- package/src/lib/design/system/sketch/baseline.js.map +1 -1
- package/src/lib/design/system/sketch/check-sketches.d.ts +1 -0
- package/src/lib/design/system/sketch/check-sketches.js +4 -2
- package/src/lib/design/system/sketch/check-sketches.js.map +1 -1
- package/src/lib/design/system/sketch/merge.js +32 -0
- package/src/lib/design/system/sketch/merge.js.map +1 -1
- package/src/lib/design/system/sketch/merged-parts.d.ts +1 -1
- package/src/lib/design/system/sketch/merged-parts.js +1 -1
- package/src/lib/design/system/sketch/merged-parts.js.map +1 -1
- package/src/lib/design/system/sketch/part-definition.d.ts +36 -0
- package/src/lib/design/system/sketch/part-definition.js +56 -2
- package/src/lib/design/system/sketch/part-definition.js.map +1 -1
- package/src/lib/design/system/sketch/sketch.d.ts +15 -0
- package/src/lib/design/system/sketch/sketch.js +65 -27
- package/src/lib/design/system/sketch/sketch.js.map +1 -1
- package/src/lib/design/system/sketch/unchanged-states.d.ts +4 -1
- package/src/lib/design/system/sketch/unchanged-states.js +9 -5
- package/src/lib/design/system/sketch/unchanged-states.js.map +1 -1
- package/src/lib/design/system/sketch/unused-closure.js +12 -2
- package/src/lib/design/system/sketch/unused-closure.js.map +1 -1
- package/src/lib/design/system/sketch/unused-files.d.ts +1 -1
- package/src/lib/design/system/sketch/unused-files.js +6 -3
- package/src/lib/design/system/sketch/unused-files.js.map +1 -1
- package/src/lib/design/system/system-tsconfig.js +2 -2
- package/src/lib/design/system/system-tsconfig.js.map +1 -1
- package/src/lib/design/system/ts-source.d.ts +3 -0
- package/src/lib/design/system/ts-source.js +21 -4
- package/src/lib/design/system/ts-source.js.map +1 -1
- package/src/lib/design/thumb.d.ts +31 -4
- package/src/lib/design/thumb.js +105 -40
- package/src/lib/design/thumb.js.map +1 -1
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
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;
|
|
12
|
+
exports.partsCompletenessOf = exports.completenessOf = exports.inventoryIdsOf = exports.seePart = exports.PLAIN_CONTROL_SELECTOR = exports.SDK_CONTROLS = exports.isMissingStateGap = exports.completenessGapLineOf = exports.completenessGapsOf = exports.findingKeyOf = exports.isFindingOf = exports.smallChangeHintsOf = exports.controlStateGapsOf = exports.isControlPart = exports.isInteractionState = exports.declaredControlsOf = void 0;
|
|
13
13
|
const fs_1 = require("fs");
|
|
14
14
|
const path_1 = require("path");
|
|
15
15
|
const browser_1 = require("../browser");
|
|
@@ -18,16 +18,18 @@ const serve_1 = require("../serve");
|
|
|
18
18
|
const shot_1 = require("../shot");
|
|
19
19
|
const thumb_1 = require("../thumb");
|
|
20
20
|
const resolve_product_1 = require("./resolve-product");
|
|
21
|
+
const contact_sheet_1 = require("../contact-sheet");
|
|
21
22
|
const baseline_1 = require("./sketch/baseline");
|
|
22
23
|
const merged_parts_1 = require("./sketch/merged-parts");
|
|
23
24
|
const system_modules_1 = require("./system-modules");
|
|
24
25
|
const exceptions_1 = require("./exceptions");
|
|
25
26
|
const inventory_approval_1 = require("./inventory-approval");
|
|
27
|
+
const option_values_1 = require("./rules/option-values");
|
|
26
28
|
const KINDS = {
|
|
27
29
|
disclosure: { surface: 'body', closed: 'collapsed' },
|
|
28
30
|
button: { adds: ['active'] },
|
|
29
|
-
select: { surface: 'open', options: true },
|
|
30
|
-
menu: { surface: 'open', options:
|
|
31
|
+
select: { surface: 'open', options: { interactions: ['hover', 'focus-visible'], selected: true } },
|
|
32
|
+
menu: { surface: 'open', options: { interactions: ['hover', 'focus-visible', 'active'], selected: false } },
|
|
31
33
|
row: { selects: true, virtualFocus: true },
|
|
32
34
|
field: { noActive: true },
|
|
33
35
|
tooltip: { surface: 'tooltip' },
|
|
@@ -88,6 +90,74 @@ const declaredControlsOf = (value) => isRecord(value)
|
|
|
88
90
|
}))
|
|
89
91
|
: null;
|
|
90
92
|
exports.declaredControlsOf = declaredControlsOf;
|
|
93
|
+
const INTERACTION_WORDS = new Set(['hover', 'hovered', 'focus', 'focused', 'pressed', 'active', 'selected']);
|
|
94
|
+
const NAME_WORDS = new Set([...INTERACTION_WORDS, 'visible', 'within', 'invalid', 'disabled', 'checked', 'open']);
|
|
95
|
+
const wordsOf = (state) => state
|
|
96
|
+
.replace(/([a-z0-9])([A-Z])/gu, '$1-$2')
|
|
97
|
+
.toLowerCase()
|
|
98
|
+
.split(/[^a-z0-9]+/u)
|
|
99
|
+
.filter((word) => word !== '');
|
|
100
|
+
/**
|
|
101
|
+
* Whether a state name shows an interaction: its last word, split at `-`, `_`, spaces and camelCase, or the whole name
|
|
102
|
+
* is hover, hovered, focus, focused, pressed, active or selected. `row-hover`, `collapseFocus` and `focus-visible`
|
|
103
|
+
* are; `active-only` and `inactive` are not.
|
|
104
|
+
*/
|
|
105
|
+
const isInteractionState = (state) => {
|
|
106
|
+
var _a, _b;
|
|
107
|
+
const words = wordsOf(state);
|
|
108
|
+
while (words.length > 1 && ['visible', 'within'].includes((_a = words[words.length - 1]) !== null && _a !== void 0 ? _a : ''))
|
|
109
|
+
words.pop();
|
|
110
|
+
return INTERACTION_WORDS.has((_b = words[words.length - 1]) !== null && _b !== void 0 ? _b : '');
|
|
111
|
+
};
|
|
112
|
+
exports.isInteractionState = isInteractionState;
|
|
113
|
+
/** Whether a part may draw interaction states: it is no page, and its `controls` declare a control of a checked kind. */
|
|
114
|
+
const isControlPart = (options) => {
|
|
115
|
+
var _a;
|
|
116
|
+
return !options.part.startsWith('pages/') &&
|
|
117
|
+
Object.values((_a = (0, exports.declaredControlsOf)(options.controls)) !== null && _a !== void 0 ? _a : {}).some((control) => CHECKED_KINDS.includes(control.kind));
|
|
118
|
+
};
|
|
119
|
+
exports.isControlPart = isControlPart;
|
|
120
|
+
/**
|
|
121
|
+
* One `CONTROL-STATE` gap per element whose interaction states a part draws that is no control part. The element is
|
|
122
|
+
* the state name without its interaction words (`row-hover` names the row), or `control` when nothing is left.
|
|
123
|
+
*/
|
|
124
|
+
const controlStateGapsOf = (options) => {
|
|
125
|
+
var _a, _b;
|
|
126
|
+
const { part, states } = options;
|
|
127
|
+
if ((0, exports.isControlPart)(options))
|
|
128
|
+
return [];
|
|
129
|
+
const elements = new Map();
|
|
130
|
+
for (const state of states.filter(exports.isInteractionState)) {
|
|
131
|
+
const element = wordsOf(state)
|
|
132
|
+
.filter((word) => !NAME_WORDS.has(word))
|
|
133
|
+
.join('-') || 'control';
|
|
134
|
+
elements.set(element, [...((_a = elements.get(element)) !== null && _a !== void 0 ? _a : []), state]);
|
|
135
|
+
}
|
|
136
|
+
const why = part.startsWith('pages/')
|
|
137
|
+
? 'a page is no control part'
|
|
138
|
+
: `${part} declares no control of a kind ${CHECKED_KINDS.join(', ')}`;
|
|
139
|
+
const declaresNone = Object.keys((_b = (0, exports.declaredControlsOf)(options.controls)) !== null && _b !== void 0 ? _b : {}).length === 0;
|
|
140
|
+
const fixOf = (element) => part.startsWith('components/') && declaresNone
|
|
141
|
+
? `declare its controls (Q164), or extract the ${element} as its own control part`
|
|
142
|
+
: `extract the ${element} as its own control part`;
|
|
143
|
+
return [...elements].map(([element, shown]) => ({
|
|
144
|
+
code: 'CONTROL-STATE',
|
|
145
|
+
target: part,
|
|
146
|
+
detail: `${shown.length === 1 ? 'state' : 'states'} ${statesShownOf(shown)} draw${shown.length === 1 ? 's' : ''} an interaction (hover, focus, pressed, active or selected), which only a control part draws, and ${why} - ${fixOf(element)} and draw ${shown.length === 1 ? 'this state' : 'these states'} there`,
|
|
147
|
+
}));
|
|
148
|
+
};
|
|
149
|
+
exports.controlStateGapsOf = controlStateGapsOf;
|
|
150
|
+
const SMALL_CHANGE = 0.1;
|
|
151
|
+
/**
|
|
152
|
+
* One hint per state of an element or component that is no control part whose pixels differ from its first state in
|
|
153
|
+
* under a tenth of the frame. Pages compose parts, so they get none; interaction states are left to `CONTROL-STATE`.
|
|
154
|
+
*/
|
|
155
|
+
const smallChangeHintsOf = (options) => options.part.startsWith('pages/') || (0, exports.isControlPart)(options)
|
|
156
|
+
? []
|
|
157
|
+
: options.changes
|
|
158
|
+
.filter(({ state, share }) => share > 0 && share < SMALL_CHANGE && !(0, exports.isInteractionState)(state))
|
|
159
|
+
.map(({ state, base, share }) => `HINT ${options.part} ${state} - changes ${(share * 100).toFixed(1)} % of the frame against ${base} - extract the changed element as its own part`);
|
|
160
|
+
exports.smallChangeHintsOf = smallChangeHintsOf;
|
|
91
161
|
/** Whether a discovered element is an undeclared or unclassified finding of the part, not owned or declared. */
|
|
92
162
|
const isFindingOf = (declared) => (found) => {
|
|
93
163
|
var _a;
|
|
@@ -98,6 +168,7 @@ const isFindingOf = (declared) => (found) => {
|
|
|
98
168
|
exports.isFindingOf = isFindingOf;
|
|
99
169
|
const findingKeyOf = (found) => `${found.kind} ${found.what} ${found.path}`;
|
|
100
170
|
exports.findingKeyOf = findingKeyOf;
|
|
171
|
+
const NATIVE_CONTROLS = ['button', 'a[href]', 'input:not([type="hidden"])', 'select', 'textarea', 'summary'];
|
|
101
172
|
const discoveryGapsOf = (options) => {
|
|
102
173
|
var _a, _b, _c, _d;
|
|
103
174
|
const { part, declared, frames } = options;
|
|
@@ -125,7 +196,9 @@ const discoveryGapsOf = (options) => {
|
|
|
125
196
|
? {
|
|
126
197
|
code: 'CONTROL-UNDECLARED',
|
|
127
198
|
target: part,
|
|
128
|
-
detail: `${where} -
|
|
199
|
+
detail: `${where} - ${NATIVE_CONTROLS.includes(found.what)
|
|
200
|
+
? 'mark it with control(markup, name) from @ethlete/components/design/control and declare the name in controls'
|
|
201
|
+
: 'mark it with data-et-control and declare it in controls'}`,
|
|
129
202
|
}
|
|
130
203
|
: {
|
|
131
204
|
code: 'CONTROL-UNCLASSIFIED',
|
|
@@ -134,6 +207,7 @@ const discoveryGapsOf = (options) => {
|
|
|
134
207
|
};
|
|
135
208
|
});
|
|
136
209
|
};
|
|
210
|
+
const isUndeclaredControlGap = (gap) => gap.code === 'CONTROL-UNDECLARED';
|
|
137
211
|
const statesShownOf = (states) => states.length > 4 ? `${states.slice(0, 3).join(', ')} and ${states.length - 3} more` : states.join(', ');
|
|
138
212
|
const overrideGapsOf = (options) => {
|
|
139
213
|
var _a, _b;
|
|
@@ -190,17 +264,26 @@ const ownersOf = (frames) => [
|
|
|
190
264
|
.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
265
|
.filter((owner) => owner !== null)),
|
|
192
266
|
];
|
|
193
|
-
const
|
|
267
|
+
const undefinedClassesGapOf = (options) => {
|
|
194
268
|
var _a;
|
|
269
|
+
const { forced, what, interaction } = options;
|
|
270
|
+
const seen = forced.find((force) => { var _a; return (_a = force.undefinedClasses) === null || _a === void 0 ? void 0 : _a.length; });
|
|
271
|
+
if (!seen)
|
|
272
|
+
return null;
|
|
273
|
+
const classes = (_a = seen.undefinedClasses) !== null && _a !== void 0 ? _a : [];
|
|
274
|
+
return `state ${seen.state} forces ${interaction} on ${what}, but no stylesheet defines its ${classes.length === 1 ? 'class' : 'classes'} ${classes.join(', ')} - Tailwind generates no utility of that name; use a colour or value the product's theme defines`;
|
|
275
|
+
};
|
|
276
|
+
const interactionGapOf = (options) => {
|
|
277
|
+
var _a, _b;
|
|
195
278
|
const { frames, id, interaction } = options;
|
|
196
279
|
const forced = frames.flatMap((frame) => frame.controls
|
|
197
280
|
.filter((control) => control.id === id)
|
|
198
281
|
.flatMap((control) => control.forced.filter((force) => force.interaction === interaction))
|
|
199
|
-
.map((force) => ({ state: frame.state, differs: force.differs })));
|
|
282
|
+
.map((force) => ({ state: frame.state, differs: force.differs, undefinedClasses: force.undefinedClasses })));
|
|
200
283
|
if (forced.some((force) => force.differs))
|
|
201
284
|
return null;
|
|
202
285
|
if (forced.length > 0)
|
|
203
|
-
return `state ${(
|
|
286
|
+
return ((_a = undefinedClassesGapOf({ forced, what: 'it', interaction })) !== null && _a !== void 0 ? _a : `state ${(_b = forced[0]) === null || _b === void 0 ? void 0 : _b.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
287
|
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
288
|
};
|
|
206
289
|
const keyboardActiveRowGapOf = (options) => {
|
|
@@ -237,12 +320,12 @@ const lookGapOf = (options) => {
|
|
|
237
320
|
return null;
|
|
238
321
|
};
|
|
239
322
|
const forcedGapOf = (options) => {
|
|
240
|
-
var _a;
|
|
323
|
+
var _a, _b;
|
|
241
324
|
const { forced, what, interaction } = options;
|
|
242
325
|
if (forced.some((force) => force.differs))
|
|
243
326
|
return null;
|
|
244
327
|
if (forced.length > 0)
|
|
245
|
-
return `state ${(
|
|
328
|
+
return ((_a = undefinedClassesGapOf(options)) !== null && _a !== void 0 ? _a : `state ${(_b = forced[0]) === null || _b === void 0 ? void 0 : _b.state} forces ${interaction} on ${what}, but its box draws no different pixel than at rest`);
|
|
246
329
|
return `no state draws ${what} ${interaction} - force ${interaction} on it, e.g. with forceInteraction`;
|
|
247
330
|
};
|
|
248
331
|
const surfaceGapsOf = (options) => {
|
|
@@ -285,19 +368,21 @@ const keyboardActiveGapOf = (options) => {
|
|
|
285
368
|
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
369
|
};
|
|
287
370
|
const optionGapsOf = (options) => {
|
|
288
|
-
const { frames, surfaceId } = options;
|
|
371
|
+
const { frames, surfaceId, interactions } = options;
|
|
289
372
|
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
373
|
const what = `an option in ${surfaceId}`;
|
|
291
374
|
const gaps = [];
|
|
292
|
-
for (const interaction of
|
|
375
|
+
for (const interaction of interactions) {
|
|
293
376
|
const forced = frames.flatMap((frame) => shownIn(frame).flatMap((option) => option.forced
|
|
294
377
|
.filter((force) => force.interaction === interaction)
|
|
295
|
-
.map((force) => ({ state: frame.state, differs: force.differs }))));
|
|
378
|
+
.map((force) => ({ state: frame.state, differs: force.differs, undefinedClasses: force.undefinedClasses }))));
|
|
296
379
|
const gap = forcedGapOf({ forced, what, interaction });
|
|
297
380
|
const missing = gap && interaction === 'focus-visible' ? keyboardActiveGapOf({ frames, shownIn, forcedGap: gap }) : gap;
|
|
298
381
|
if (missing)
|
|
299
382
|
gaps.push([`option-${interaction}`, missing]);
|
|
300
383
|
}
|
|
384
|
+
if (!options.selected)
|
|
385
|
+
return gaps;
|
|
301
386
|
const seen = frames
|
|
302
387
|
.filter((frame) => frame.interaction === null)
|
|
303
388
|
.flatMap((frame) => shownIn(frame)
|
|
@@ -334,7 +419,7 @@ const requirementGapsOf = (options) => {
|
|
|
334
419
|
const forced = frames.flatMap((frame) => frame.controls
|
|
335
420
|
.filter((seen) => seen.id === id && seen.selected)
|
|
336
421
|
.flatMap((seen) => seen.forced.filter((force) => force.interaction === 'hover'))
|
|
337
|
-
.map((force) => ({ state: frame.state, differs: force.differs })));
|
|
422
|
+
.map((force) => ({ state: frame.state, differs: force.differs, undefinedClasses: force.undefinedClasses })));
|
|
338
423
|
const hovered = forcedGapOf({ forced, what: 'it selected', interaction: 'hover' });
|
|
339
424
|
if (selected)
|
|
340
425
|
gaps.push(['selected', selected]);
|
|
@@ -354,7 +439,7 @@ const requirementGapsOf = (options) => {
|
|
|
354
439
|
if (kind.surface)
|
|
355
440
|
gaps.push(...surfaceGapsOf(Object.assign(Object.assign({}, options), { surface: kind.surface, closed: kind.closed })));
|
|
356
441
|
if (own && kind.options && kind.surface)
|
|
357
|
-
gaps.push(...optionGapsOf({ frames, surfaceId: `${id}.${kind.surface}` }));
|
|
442
|
+
gaps.push(...optionGapsOf(Object.assign({ frames, surfaceId: `${id}.${kind.surface}` }, kind.options)));
|
|
358
443
|
return gaps;
|
|
359
444
|
};
|
|
360
445
|
/**
|
|
@@ -431,7 +516,7 @@ const completenessGapsOf = (options) => {
|
|
|
431
516
|
}
|
|
432
517
|
return [
|
|
433
518
|
...gaps,
|
|
434
|
-
...discoveryGapsOf({ part, declared, frames }),
|
|
519
|
+
...discoveryGapsOf({ part, declared, frames }).filter((gap) => !isUndeclaredControlGap(gap)),
|
|
435
520
|
...ownerGapsOf({ part, declared, frames, referenced }),
|
|
436
521
|
...overrideGapsOf({ part, frames }),
|
|
437
522
|
...inventoryGapsOf({ part, inventory }),
|
|
@@ -446,6 +531,10 @@ const inventoryGapsOf = ({ part, inventory }) => {
|
|
|
446
531
|
};
|
|
447
532
|
const completenessGapLineOf = (gap) => `${gap.code} ${gap.target} - ${gap.detail}`;
|
|
448
533
|
exports.completenessGapLineOf = completenessGapLineOf;
|
|
534
|
+
const MISSING_STATE_CODES = ['CONTROL-UNDRAWN', 'CONTROL-GRID-MISSING', 'REQUIREMENT-MISSING'];
|
|
535
|
+
/** Whether a gap is a declared control that no state draws, or that lacks a drawn interaction, look or surface. */
|
|
536
|
+
const isMissingStateGap = (gap) => MISSING_STATE_CODES.includes(gap.code);
|
|
537
|
+
exports.isMissingStateGap = isMissingStateGap;
|
|
449
538
|
const NO_MOTION = '*, *::before, *::after { transition: none !important; animation: none !important; }';
|
|
450
539
|
const PAD = 8;
|
|
451
540
|
const COLOUR_PROPERTIES = [
|
|
@@ -489,6 +578,28 @@ const coversOf = (property) => {
|
|
|
489
578
|
return ['all', 'border', 'border-color', property.replace(/-color$/, ''), property];
|
|
490
579
|
return ['all', property];
|
|
491
580
|
};
|
|
581
|
+
const undefinedVariantClasses = (at) => `((at) => {
|
|
582
|
+
const control = document.querySelector('[data-et-complete="' + at + '"]');
|
|
583
|
+
const selectors = [];
|
|
584
|
+
const collect = (rules) => {
|
|
585
|
+
for (const rule of rules) {
|
|
586
|
+
if (rule.selectorText) selectors.push(rule.selectorText);
|
|
587
|
+
if (rule.cssRules) collect(rule.cssRules);
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
for (const sheet of document.styleSheets) {
|
|
591
|
+
try {
|
|
592
|
+
collect(sheet.cssRules);
|
|
593
|
+
} catch {}
|
|
594
|
+
}
|
|
595
|
+
const tokens = new Set([control, ...control.querySelectorAll('*')].flatMap((element) => [...element.classList]));
|
|
596
|
+
return [...tokens].filter((token) => token.includes(':') && !selectors.some((selector) => selector.includes('.' + CSS.escape(token))));
|
|
597
|
+
})(${JSON.stringify(at)})`;
|
|
598
|
+
const VARIANT_WORDS = { hover: 'hover', active: 'active', 'focus-visible': 'focus' };
|
|
599
|
+
const isVariantOf = (token, interaction) => token
|
|
600
|
+
.split(':')
|
|
601
|
+
.slice(0, -1)
|
|
602
|
+
.some((variant) => { var _a; return variant.includes((_a = VARIANT_WORDS[interaction]) !== null && _a !== void 0 ? _a : interaction); });
|
|
492
603
|
const stillChangesOf = (rest, forced) => forced.names.flatMap((name, element) => {
|
|
493
604
|
var _a;
|
|
494
605
|
const { properties, durations } = (_a = forced.transitions[element]) !== null && _a !== void 0 ? _a : { properties: [], durations: [] };
|
|
@@ -526,7 +637,7 @@ const INTERACTIVE_ROLES = [
|
|
|
526
637
|
'textbox',
|
|
527
638
|
'treeitem',
|
|
528
639
|
];
|
|
529
|
-
|
|
640
|
+
exports.SDK_CONTROLS = [
|
|
530
641
|
'[et-button]',
|
|
531
642
|
'[et-icon-button]',
|
|
532
643
|
'[et-text-button]',
|
|
@@ -566,23 +677,22 @@ const SDK_CONTROLS = [
|
|
|
566
677
|
'et-time-input',
|
|
567
678
|
'et-toggletip',
|
|
568
679
|
];
|
|
569
|
-
const
|
|
570
|
-
|
|
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
|
-
];
|
|
680
|
+
const PLAIN_CONTROLS = [...NATIVE_CONTROLS, '[tabindex]', ...INTERACTIVE_ROLES.map((role) => `[role="${role}"]`)];
|
|
681
|
+
const LIKELY_CONTROLS = [...exports.SDK_CONTROLS, ...PLAIN_CONTROLS];
|
|
580
682
|
const LOOK_PROPERTIES = [...COLOUR_PROPERTIES, 'opacity', 'box-shadow', 'font-weight', 'text-decoration-line'];
|
|
581
683
|
const OPTION_SELECTOR = '[role="option"], [role^="menuitem"], [data-et-option]';
|
|
684
|
+
const COMPOSITE_ROLES = ['grid', 'listbox', 'menu', 'menubar', 'radiogroup', 'tablist', 'tree', 'treegrid'];
|
|
685
|
+
const FOCUS_CONTAINER = COMPOSITE_ROLES.flatMap((role) => [
|
|
686
|
+
`[role="${role}"][tabindex="-1"]`,
|
|
687
|
+
`[role="${role}"][aria-activedescendant]`,
|
|
688
|
+
]).join(', ');
|
|
689
|
+
exports.PLAIN_CONTROL_SELECTOR = `:is(${PLAIN_CONTROLS.join(', ')}):not(${FOCUS_CONTAINER})`;
|
|
582
690
|
const discoverControls = `((root) => {
|
|
583
691
|
const LIKELY = ${JSON.stringify(LIKELY_CONTROLS)};
|
|
584
692
|
const likely = LIKELY.join(', ');
|
|
585
|
-
const
|
|
693
|
+
const container = ${JSON.stringify(FOCUS_CONTAINER)};
|
|
694
|
+
const isLikely = (element) => element.matches(likely) && !element.matches(container);
|
|
695
|
+
const sdk = ${JSON.stringify(exports.SDK_CONTROLS.join(', '))};
|
|
586
696
|
const rendered = (element) => element.getClientRects().length > 0;
|
|
587
697
|
const HOVER = /(?<!\\\\):hover(?![\\w-])/g;
|
|
588
698
|
const FORCED_HOVER = /:is\\(:hover,\\s*\\[data-et-force~="?hover"?\\]\\)/g;
|
|
@@ -640,7 +750,7 @@ const discoverControls = `((root) => {
|
|
|
640
750
|
const markedOf = (element) => {
|
|
641
751
|
if (element.hasAttribute('data-et-control')) return element.getAttribute('data-et-control');
|
|
642
752
|
for (let at = element.parentElement; at && at !== root; at = at.parentElement) {
|
|
643
|
-
if (at
|
|
753
|
+
if (isLikely(at)) return null;
|
|
644
754
|
const id = markerOf(at, element);
|
|
645
755
|
if (id !== null) return id;
|
|
646
756
|
}
|
|
@@ -649,7 +759,7 @@ const discoverControls = `((root) => {
|
|
|
649
759
|
const found = [];
|
|
650
760
|
for (const element of root.querySelectorAll('*')) {
|
|
651
761
|
if (!rendered(element)) continue;
|
|
652
|
-
const what = LIKELY.find((selector) => element.matches(selector));
|
|
762
|
+
const what = !element.matches(container) && LIKELY.find((selector) => element.matches(selector));
|
|
653
763
|
if (what) {
|
|
654
764
|
const inSdk = element.parentElement.closest(sdk);
|
|
655
765
|
if (inSdk !== null && root.contains(inSdk)) continue;
|
|
@@ -659,7 +769,9 @@ const discoverControls = `((root) => {
|
|
|
659
769
|
const cursor = getComputedStyle(element).cursor;
|
|
660
770
|
const pointer = cursor === 'pointer' && getComputedStyle(element.parentElement).cursor !== 'pointer';
|
|
661
771
|
if (!pointer && !hovered.has(element)) continue;
|
|
662
|
-
|
|
772
|
+
let inControl = false;
|
|
773
|
+
for (let at = element; at && !inControl; at = at.parentElement) inControl = at.hasAttribute('data-et-control') || isLikely(at);
|
|
774
|
+
if (inControl) continue;
|
|
663
775
|
const reason = [pointer ? 'cursor: pointer' : '', hovered.has(element) ? ':hover rule' : ''].filter(Boolean).join(' and ');
|
|
664
776
|
found.push({ kind: 'unclassified', what: nameOf(element) + ' with ' + reason, path: pathOf(element), marked: null, within: [], owner: ownerOf(element)?.key ?? null, box: frameBoxOf(element) });
|
|
665
777
|
}
|
|
@@ -819,7 +931,7 @@ const seeFrame = (options) => `(() => {
|
|
|
819
931
|
const isKeyboard = (element) => element.getAttribute('data-active-source') === 'keyboard';
|
|
820
932
|
let next = 0;
|
|
821
933
|
const tagged = (element) => {
|
|
822
|
-
const at = next++;
|
|
934
|
+
const at = element.hasAttribute('data-et-complete') ? Number(element.getAttribute('data-et-complete')) : next++;
|
|
823
935
|
element.setAttribute('data-et-complete', String(at));
|
|
824
936
|
const box = element.getBoundingClientRect();
|
|
825
937
|
const x = Math.max(0, box.x + scrollX - ${PAD});
|
|
@@ -873,6 +985,7 @@ const seeFrames = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
873
985
|
const context = yield browser.newContext();
|
|
874
986
|
const seen = [];
|
|
875
987
|
const refused = [];
|
|
988
|
+
const shots = [];
|
|
876
989
|
try {
|
|
877
990
|
const page = yield context.newPage();
|
|
878
991
|
for (const frame of frames) {
|
|
@@ -885,6 +998,13 @@ const seeFrames = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
885
998
|
refused.push(`${frame.state}: ${found.refused}`);
|
|
886
999
|
continue;
|
|
887
1000
|
}
|
|
1001
|
+
if (frame.interaction === null) {
|
|
1002
|
+
const box = frame.clip ? yield page.locator('#root').boundingBox() : null;
|
|
1003
|
+
shots.push({
|
|
1004
|
+
state: frame.state,
|
|
1005
|
+
png: yield page.screenshot({ type: 'png', fullPage: true, animations: 'disabled', clip: box !== null && box !== void 0 ? box : undefined }),
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
888
1008
|
const forcedOf = (element) => __awaiter(void 0, void 0, void 0, function* () {
|
|
889
1009
|
const forced = [];
|
|
890
1010
|
for (const interaction of element.forced.filter((name) => FORCEABLE.has(name))) {
|
|
@@ -900,11 +1020,12 @@ const seeFrames = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
900
1020
|
const rest = yield shot();
|
|
901
1021
|
const restColours = (yield page.evaluate(colourSnapshot(element.at)));
|
|
902
1022
|
yield page.evaluate(forceOn({ at: element.at, interaction, on: true }));
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
1023
|
+
const differs = !drawn.equals(rest);
|
|
1024
|
+
const undefinedClasses = differs
|
|
1025
|
+
? []
|
|
1026
|
+
: (yield page.evaluate(undefinedVariantClasses(element.at))).filter((token) => isVariantOf(token, interaction));
|
|
1027
|
+
forced.push(Object.assign({ interaction,
|
|
1028
|
+
differs, still: stillChangesOf(restColours, drawnColours) }, (undefinedClasses.length > 0 ? { undefinedClasses } : {})));
|
|
908
1029
|
}
|
|
909
1030
|
return forced;
|
|
910
1031
|
});
|
|
@@ -931,7 +1052,20 @@ const seeFrames = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
931
1052
|
finally {
|
|
932
1053
|
yield context.close();
|
|
933
1054
|
}
|
|
934
|
-
|
|
1055
|
+
const [first, ...others] = shots;
|
|
1056
|
+
const shares = first ? yield (0, contact_sheet_1.changedSharesOf)({ browser, base: first.png, others: others.map(({ png }) => png) }) : [];
|
|
1057
|
+
return {
|
|
1058
|
+
seen,
|
|
1059
|
+
refused,
|
|
1060
|
+
changes: others.map(({ state }, index) => {
|
|
1061
|
+
var _a, _b;
|
|
1062
|
+
return ({
|
|
1063
|
+
state,
|
|
1064
|
+
base: (_a = first === null || first === void 0 ? void 0 : first.state) !== null && _a !== void 0 ? _a : '',
|
|
1065
|
+
share: (_b = shares[index]) !== null && _b !== void 0 ? _b : 0,
|
|
1066
|
+
});
|
|
1067
|
+
}),
|
|
1068
|
+
};
|
|
935
1069
|
});
|
|
936
1070
|
/**
|
|
937
1071
|
* Draws every state of one part of the product, at rest and, unless `restOnly`, in each interaction it declares,
|
|
@@ -984,13 +1118,14 @@ const seePart = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
984
1118
|
.filter((file) => file.endsWith('.css'))
|
|
985
1119
|
.sort()
|
|
986
1120
|
.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 }));
|
|
1121
|
+
const { seen, refused, changes } = yield draw((browser) => seeFrames({ browser, base, frames, part: key, ownCss }));
|
|
988
1122
|
const owner = (0, inventory_approval_1.partOwnerOf)({ product, part });
|
|
989
1123
|
return {
|
|
990
1124
|
definition,
|
|
991
1125
|
states,
|
|
992
1126
|
seen,
|
|
993
1127
|
refused,
|
|
1128
|
+
changes,
|
|
994
1129
|
addresses: states.map((state) => ({ state, preset, width })),
|
|
995
1130
|
owner,
|
|
996
1131
|
hash: (0, baseline_1.partHashOf)({ product: owner, dir }),
|
|
@@ -1005,23 +1140,45 @@ exports.inventoryIdsOf = inventoryIdsOf;
|
|
|
1005
1140
|
/**
|
|
1006
1141
|
* Draws every state of one part, at rest and in each interaction it declares, once at its first preset or width,
|
|
1007
1142
|
* 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
|
|
1143
|
+
* and an embedded part whose `data-et-part` root draws a control, is checked the same way, and its gaps fail it -
|
|
1144
|
+
* unless it is a part of the product's base, whose gaps stay its own.
|
|
1009
1145
|
* A page fails until the user approves its control inventory in Studio. An exception the user approved in Studio
|
|
1010
1146
|
* drops the gap it names until the part changes; a pending one still fails. With `sketch`, every part is drawn as
|
|
1011
1147
|
* that variant draws it, and a part the variant changes is not merged yet, so it never fails as unreviewed.
|
|
1148
|
+
* A drawn control that no `controls` entry declares is a hint; the sketch check fails on one a sketch adds.
|
|
1012
1149
|
*/
|
|
1013
1150
|
const completenessOf = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1014
1151
|
var _a, _b, _c, _d;
|
|
1015
1152
|
const { target, config, product, part, sketch = null } = options;
|
|
1016
|
-
const resolveChromium = (_a = options.chromiumOf) !== null && _a !== void 0 ? _a : browser_1.chromiumOf;
|
|
1017
1153
|
const system = (0, system_modules_1.createSystemModules)({ target, config });
|
|
1018
|
-
const parts = (
|
|
1154
|
+
const parts = (_b = (_a = (sketch ? system.drawnOf(product.name, sketch) : product)) === null || _a === void 0 ? void 0 : _a.parts) !== null && _b !== void 0 ? _b : [];
|
|
1019
1155
|
if (!parts.some((candidate) => (0, resolve_product_1.partKeyOf)(candidate) === part))
|
|
1020
1156
|
return {
|
|
1021
1157
|
problem: sketch
|
|
1022
1158
|
? `variant "${sketch.variant}" of the sketch on ${sketch.target} in product "${product.name}" has no part "${part}"`
|
|
1023
1159
|
: `product "${product.name}" has no part "${part}"`,
|
|
1024
1160
|
};
|
|
1161
|
+
const checked = yield (0, exports.partsCompletenessOf)(Object.assign(Object.assign({}, options), { parts: [part] }));
|
|
1162
|
+
if ('unavailable' in checked)
|
|
1163
|
+
return checked;
|
|
1164
|
+
const gaps = (_c = checked.gaps.get(part)) !== null && _c !== void 0 ? _c : [];
|
|
1165
|
+
if (typeof gaps === 'string')
|
|
1166
|
+
return { problem: gaps };
|
|
1167
|
+
const hints = (_d = checked.hints.get(part)) !== null && _d !== void 0 ? _d : [];
|
|
1168
|
+
return Object.assign(Object.assign({ gaps }, (checked.exceptions.length > 0 ? { exceptions: checked.exceptions } : {})), (hints.length > 0 ? { hints } : {}));
|
|
1169
|
+
});
|
|
1170
|
+
exports.completenessOf = completenessOf;
|
|
1171
|
+
/**
|
|
1172
|
+
* Checks each named part as `completenessOf` does, sharing one server, browser and cache, and answers the gaps of
|
|
1173
|
+
* each part, or why it could not be checked as a string.
|
|
1174
|
+
*/
|
|
1175
|
+
const partsCompletenessOf = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1176
|
+
var _a, _b, _c, _d;
|
|
1177
|
+
const { target, config, product, sketch = null } = options;
|
|
1178
|
+
const resolveChromium = (_a = options.chromiumOf) !== null && _a !== void 0 ? _a : browser_1.chromiumOf;
|
|
1179
|
+
const system = (0, system_modules_1.createSystemModules)({ target, config });
|
|
1180
|
+
const parts = (_c = (_b = (sketch ? system.drawnOf(product.name, sketch) : product)) === null || _b === void 0 ? void 0 : _b.parts) !== null && _c !== void 0 ? _c : [];
|
|
1181
|
+
const optionValuesOf = (0, option_values_1.optionValuesChecker)({ target, config, parts });
|
|
1025
1182
|
if (!(yield resolveChromium(target)))
|
|
1026
1183
|
return { unavailable: 'neither the checkout nor this package resolves playwright or playwright-core' };
|
|
1027
1184
|
const queue = (0, thumb_1.createDrawQueue)({ target, chromiumOf: resolveChromium });
|
|
@@ -1031,6 +1188,7 @@ const completenessOf = (options) => __awaiter(void 0, void 0, void 0, function*
|
|
|
1031
1188
|
const { port } = (_d = server.httpServer) === null || _d === void 0 ? void 0 : _d.address();
|
|
1032
1189
|
const checked = new Map();
|
|
1033
1190
|
const exceptions = [];
|
|
1191
|
+
const hints = new Map();
|
|
1034
1192
|
const gapsOfPart = (key, chain) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1035
1193
|
const known = checked.get(key);
|
|
1036
1194
|
if (known !== undefined && !chain.includes(key))
|
|
@@ -1040,7 +1198,7 @@ const completenessOf = (options) => __awaiter(void 0, void 0, void 0, function*
|
|
|
1040
1198
|
return gaps;
|
|
1041
1199
|
});
|
|
1042
1200
|
const freshGapsOfPart = (key, chain) => __awaiter(void 0, void 0, void 0, function* () {
|
|
1043
|
-
var _a, _b, _c;
|
|
1201
|
+
var _a, _b, _c, _d;
|
|
1044
1202
|
const resolved = parts.find((candidate) => (0, resolve_product_1.partKeyOf)(candidate) === key);
|
|
1045
1203
|
if (!resolved)
|
|
1046
1204
|
return `product "${product.name}" has no part "${key}"`;
|
|
@@ -1057,17 +1215,29 @@ const completenessOf = (options) => __awaiter(void 0, void 0, void 0, function*
|
|
|
1057
1215
|
});
|
|
1058
1216
|
if (typeof sight === 'string')
|
|
1059
1217
|
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
|
|
1218
|
+
const { definition, states, seen, refused, changes, owner, hash } = sight;
|
|
1219
|
+
const optionProblems = optionValuesOf(resolved, definition !== null && definition !== void 0 ? definition : {});
|
|
1220
|
+
hints.set(key, [
|
|
1221
|
+
...(0, exports.smallChangeHintsOf)({ part: key, controls: definition === null || definition === void 0 ? void 0 : definition.controls, changes }),
|
|
1222
|
+
...(0, exports.controlStateGapsOf)({ part: key, controls: definition === null || definition === void 0 ? void 0 : definition.controls, states }).map(exports.completenessGapLineOf),
|
|
1223
|
+
...discoveryGapsOf({ part: key, declared: (_b = (0, exports.declaredControlsOf)(definition === null || definition === void 0 ? void 0 : definition.controls)) !== null && _b !== void 0 ? _b : {}, frames: seen })
|
|
1224
|
+
.filter(isUndeclaredControlGap)
|
|
1225
|
+
.map(exports.completenessGapLineOf),
|
|
1226
|
+
...optionProblems
|
|
1227
|
+
.filter((gap) => gap.code === 'OPTION-VALUE-MISSING')
|
|
1228
|
+
.map((gap) => (0, exports.completenessGapLineOf)(Object.assign(Object.assign({}, gap), { target: key }))),
|
|
1229
|
+
]);
|
|
1230
|
+
const sketched = ((_c = product.parts.find((candidate) => (0, resolve_product_1.partKeyOf)(candidate) === key)) === null || _c === void 0 ? void 0 : _c.file) !== resolved.file;
|
|
1062
1231
|
const reviewed = sketched || (0, merged_parts_1.readMerged)(owner.dir)[key] === hash;
|
|
1063
1232
|
const referenced = {};
|
|
1064
1233
|
const used = [
|
|
1065
|
-
...Object.values((
|
|
1234
|
+
...Object.values((_d = (0, exports.declaredControlsOf)(definition === null || definition === void 0 ? void 0 : definition.controls)) !== null && _d !== void 0 ? _d : {}).map((control) => control.part),
|
|
1066
1235
|
...ownersOf(seen),
|
|
1067
1236
|
];
|
|
1237
|
+
const isKitPart = (other) => { var _a; return resolved.origin !== 'base' && ((_a = parts.find((candidate) => (0, resolve_product_1.partKeyOf)(candidate) === other)) === null || _a === void 0 ? void 0 : _a.origin) === 'base'; };
|
|
1068
1238
|
for (const other of used)
|
|
1069
1239
|
if (other !== null && !(other in referenced))
|
|
1070
|
-
referenced[other] = yield gapsOfPart(other, [...chain, key]);
|
|
1240
|
+
referenced[other] = isKitPart(other) ? [] : yield gapsOfPart(other, [...chain, key]);
|
|
1071
1241
|
const excepted = (0, exceptions_1.withExceptions)({
|
|
1072
1242
|
part: key,
|
|
1073
1243
|
exceptions: (0, exceptions_1.readExceptions)(owner.dir),
|
|
@@ -1086,12 +1256,16 @@ const completenessOf = (options) => __awaiter(void 0, void 0, void 0, function*
|
|
|
1086
1256
|
}),
|
|
1087
1257
|
});
|
|
1088
1258
|
exceptions.push(...excepted.listed);
|
|
1089
|
-
return [
|
|
1259
|
+
return [
|
|
1260
|
+
...refused.map((detail) => ({ code: 'RENDER', target: key, detail })),
|
|
1261
|
+
...optionProblems.filter((gap) => gap.code !== 'OPTION-VALUE-MISSING').map((gap) => (Object.assign(Object.assign({}, gap), { target: key }))),
|
|
1262
|
+
...excepted.gaps,
|
|
1263
|
+
];
|
|
1090
1264
|
});
|
|
1091
|
-
const gaps =
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
return
|
|
1265
|
+
const gaps = new Map();
|
|
1266
|
+
for (const part of options.parts)
|
|
1267
|
+
gaps.set(part, yield gapsOfPart(part, []));
|
|
1268
|
+
return { gaps, exceptions, hints };
|
|
1095
1269
|
}
|
|
1096
1270
|
catch (error) {
|
|
1097
1271
|
if (error instanceof thumb_1.ThumbUnavailableError)
|
|
@@ -1102,5 +1276,5 @@ const completenessOf = (options) => __awaiter(void 0, void 0, void 0, function*
|
|
|
1102
1276
|
yield Promise.all([queue.close(), server.close()]);
|
|
1103
1277
|
}
|
|
1104
1278
|
});
|
|
1105
|
-
exports.
|
|
1279
|
+
exports.partsCompletenessOf = partsCompletenessOf;
|
|
1106
1280
|
//# sourceMappingURL=complete.js.map
|