raven-mcp 1.12.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/dist/audit-consistency.d.ts +0 -52
- package/dist/audit-consistency.js +0 -290
- package/dist/audit-consistency.js.map +0 -1
- package/dist/layout-orphans.d.ts +0 -36
- package/dist/layout-orphans.js +0 -119
- package/dist/layout-orphans.js.map +0 -1
- package/dist/score-page.d.ts +0 -36
- package/dist/score-page.js +0 -95
- package/dist/score-page.js.map +0 -1
- package/dist/video-playback.d.ts +0 -61
- package/dist/video-playback.js +0 -201
- package/dist/video-playback.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "raven-mcp",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"mcpName": "ai.ravenmcp/raven-mcp",
|
|
5
5
|
"description": "Design intelligence and creative orchestration MCP server — principles, patterns, tokens, audits, brand guidance, local brand profiles, assets, campaign plans, and provider-agnostic image/video/3D/audio generation jobs.",
|
|
6
6
|
"type": "module",
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
export type ConsistencyDimension = {
|
|
2
|
-
reference: string | null;
|
|
3
|
-
source: "token" | "modal" | "none";
|
|
4
|
-
outliers: string[];
|
|
5
|
-
};
|
|
6
|
-
export type ConsistencyIssue = {
|
|
7
|
-
severity: "warning";
|
|
8
|
-
rule: string;
|
|
9
|
-
message: string;
|
|
10
|
-
fix: string;
|
|
11
|
-
};
|
|
12
|
-
export type ConsistencyPageResult = {
|
|
13
|
-
name: string;
|
|
14
|
-
container: {
|
|
15
|
-
px: number | null;
|
|
16
|
-
classes: string[];
|
|
17
|
-
signature: string;
|
|
18
|
-
};
|
|
19
|
-
hero: {
|
|
20
|
-
size_px: number | null;
|
|
21
|
-
classes: string;
|
|
22
|
-
signature: string;
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
export type ConsistencyResult = {
|
|
26
|
-
page_count: number;
|
|
27
|
-
pages: ConsistencyPageResult[];
|
|
28
|
-
consistency: {
|
|
29
|
-
container: ConsistencyDimension;
|
|
30
|
-
hero: ConsistencyDimension;
|
|
31
|
-
};
|
|
32
|
-
issues: ConsistencyIssue[];
|
|
33
|
-
score: number;
|
|
34
|
-
grade: "A" | "B" | "C" | "D";
|
|
35
|
-
summary: string;
|
|
36
|
-
};
|
|
37
|
-
export type AuditConsistencyOptions = {
|
|
38
|
-
container_token?: number;
|
|
39
|
-
hero_token?: string;
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Audit multiple pages for cross-page consistency of:
|
|
43
|
-
* - Content-container width (container_px / container_classes)
|
|
44
|
-
* - Hero heading tier (hero_size_px / hero_classes)
|
|
45
|
-
*
|
|
46
|
-
* Infers the canonical (modal) value from the corpus when no token is supplied.
|
|
47
|
-
* Pure — no I/O, no browser. Assumes pages.length >= 2.
|
|
48
|
-
*/
|
|
49
|
-
export declare function auditConsistency(pages: Array<{
|
|
50
|
-
name: string;
|
|
51
|
-
html: string;
|
|
52
|
-
}>, opts?: AuditConsistencyOptions): ConsistencyResult;
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
// ── Cross-page consistency audit ─────────────────────────────────────
|
|
2
|
-
//
|
|
3
|
-
// Accepts multiple pages (name + HTML string) and flags cross-page
|
|
4
|
-
// divergence in (a) content-container width and (b) hero heading tier.
|
|
5
|
-
// The canonical (reference) value for each dimension is inferred from the
|
|
6
|
-
// corpus modal when no token is supplied, so callers need not know the
|
|
7
|
-
// project's token in advance.
|
|
8
|
-
//
|
|
9
|
-
// Pure HTML-string analysis: no I/O, no browser.
|
|
10
|
-
// Reuses `containerScaleWidths` from audit-container.ts; does NOT modify it.
|
|
11
|
-
//
|
|
12
|
-
// Addresses GitHub issue #9 ("single-blob audit blind spot") — fix #1
|
|
13
|
-
// (multi-page / corpus audit mode).
|
|
14
|
-
import { containerScaleWidths } from "./audit-container.js";
|
|
15
|
-
// ── Per-page extraction helpers ──────────────────────────────────────
|
|
16
|
-
var CONTAINER_CLASS_RE = /\b(max-w-[a-z0-9.]+|container[a-z0-9-]*|w-screen|w-full)\b/gi;
|
|
17
|
-
/**
|
|
18
|
-
* Extract container-class tokens from the page HTML.
|
|
19
|
-
* Returns a sorted, unique array of class tokens matching the pattern.
|
|
20
|
-
*/
|
|
21
|
-
function extractContainerClasses(html) {
|
|
22
|
-
var found = [];
|
|
23
|
-
var m;
|
|
24
|
-
var re = new RegExp(CONTAINER_CLASS_RE.source, "gi");
|
|
25
|
-
while ((m = re.exec(html)) !== null) {
|
|
26
|
-
found.push(m[0].toLowerCase());
|
|
27
|
-
}
|
|
28
|
-
// Sort + deduplicate
|
|
29
|
-
var unique = Array.from(new Set(found)).sort();
|
|
30
|
-
return unique;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Largest declared heading font-size in px among h1/h2 CSS rules, or null.
|
|
34
|
-
* Mirrors the approach in page-checks.ts lines ~135-138: regex for h1/h2 CSS
|
|
35
|
-
* rules then pulls the font-size value.
|
|
36
|
-
*/
|
|
37
|
-
function extractHeroSizePx(html) {
|
|
38
|
-
var best = null;
|
|
39
|
-
var tags = ["h1", "h2"];
|
|
40
|
-
for (var i = 0; i < tags.length; i++) {
|
|
41
|
-
var ht = tags[i];
|
|
42
|
-
var hre = new RegExp("(?:^|[\\s,}])" + ht + "\\b[^{]*\\{[^}]*font-size\\s*:\\s*(\\d+(?:\\.\\d+)?)\\s*px", "i");
|
|
43
|
-
var hm = html.match(hre);
|
|
44
|
-
if (hm) {
|
|
45
|
-
var n = parseFloat(hm[1]);
|
|
46
|
-
if (!isNaN(n) && (best === null || n > best))
|
|
47
|
-
best = n;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return best;
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Extract the class attribute of the FIRST <h1 ...> tag in the page.
|
|
54
|
-
* Returns "" if none found or no class attr present.
|
|
55
|
-
*/
|
|
56
|
-
function extractFirstH1Classes(html) {
|
|
57
|
-
var m = html.match(/<h1\b([^>]*)>/i);
|
|
58
|
-
if (!m)
|
|
59
|
-
return "";
|
|
60
|
-
var attrs = m[1];
|
|
61
|
-
var classMatch = attrs.match(/\bclass\s*=\s*(?:"([^"]*?)"|'([^']*?)'|([^\s>]*))/i);
|
|
62
|
-
if (!classMatch)
|
|
63
|
-
return "";
|
|
64
|
-
return (classMatch[1] || classMatch[2] || classMatch[3] || "").trim();
|
|
65
|
-
}
|
|
66
|
-
var HERO_TYPE_SCALE_RE = /\btext-(display-[a-z0-9]+|[0-9]?xl|xs|sm|base|lg|xl)\b/i;
|
|
67
|
-
/**
|
|
68
|
-
* Derive the hero signature for a page.
|
|
69
|
-
* If hero_size_px is known, use that as the signature (e.g. "64").
|
|
70
|
-
* Else find the first type-scale class in hero_classes.
|
|
71
|
-
* Else "".
|
|
72
|
-
*/
|
|
73
|
-
function heroSignature(heroPx, heroClasses) {
|
|
74
|
-
if (heroPx !== null)
|
|
75
|
-
return String(heroPx);
|
|
76
|
-
var m = heroClasses.match(HERO_TYPE_SCALE_RE);
|
|
77
|
-
if (m)
|
|
78
|
-
return m[0];
|
|
79
|
-
return "";
|
|
80
|
-
}
|
|
81
|
-
// ── Per-page extraction ───────────────────────────────────────────────
|
|
82
|
-
function extractPage(name, html) {
|
|
83
|
-
// Container
|
|
84
|
-
var widths = containerScaleWidths(html);
|
|
85
|
-
var containerPx = widths.length > 0 ? Math.max.apply(null, widths) : null;
|
|
86
|
-
var containerClasses = extractContainerClasses(html);
|
|
87
|
-
var containerSignature;
|
|
88
|
-
if (containerPx !== null) {
|
|
89
|
-
containerSignature = String(containerPx);
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
containerSignature = containerClasses.join(" ");
|
|
93
|
-
}
|
|
94
|
-
// Hero
|
|
95
|
-
var heroPx = extractHeroSizePx(html);
|
|
96
|
-
var heroClasses = extractFirstH1Classes(html);
|
|
97
|
-
var herSig = heroSignature(heroPx, heroClasses);
|
|
98
|
-
return {
|
|
99
|
-
name: name,
|
|
100
|
-
container: {
|
|
101
|
-
px: containerPx,
|
|
102
|
-
classes: containerClasses,
|
|
103
|
-
signature: containerSignature
|
|
104
|
-
},
|
|
105
|
-
hero: {
|
|
106
|
-
size_px: heroPx,
|
|
107
|
-
classes: heroClasses,
|
|
108
|
-
signature: herSig
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
// ── Modal inference ───────────────────────────────────────────────────
|
|
113
|
-
/**
|
|
114
|
-
* Find the modal (most frequent) value among non-empty strings.
|
|
115
|
-
* Returns null if all are empty, or if there's a tie among ≥2 distinct values.
|
|
116
|
-
*/
|
|
117
|
-
function findModal(values) {
|
|
118
|
-
var nonEmpty = values.filter(function (v) { return v !== ""; });
|
|
119
|
-
if (nonEmpty.length === 0)
|
|
120
|
-
return null;
|
|
121
|
-
var counts = {};
|
|
122
|
-
for (var i = 0; i < nonEmpty.length; i++) {
|
|
123
|
-
var v = nonEmpty[i];
|
|
124
|
-
counts[v] = (counts[v] || 0) + 1;
|
|
125
|
-
}
|
|
126
|
-
var maxCount = 0;
|
|
127
|
-
var keys = Object.keys(counts);
|
|
128
|
-
for (var k = 0; k < keys.length; k++) {
|
|
129
|
-
if (counts[keys[k]] > maxCount)
|
|
130
|
-
maxCount = counts[keys[k]];
|
|
131
|
-
}
|
|
132
|
-
// All values with the max count
|
|
133
|
-
var leaders = keys.filter(function (k) { return counts[k] === maxCount; });
|
|
134
|
-
// Tie among ≥2 distinct values → no modal
|
|
135
|
-
if (leaders.length >= 2)
|
|
136
|
-
return null;
|
|
137
|
-
return leaders[0];
|
|
138
|
-
}
|
|
139
|
-
function checkDimension(pageNames, signatures, token) {
|
|
140
|
-
// All non-empty signatures
|
|
141
|
-
var nonEmpty = signatures.filter(function (s) { return s !== ""; });
|
|
142
|
-
// 1. Token override
|
|
143
|
-
if (token !== undefined && token !== null) {
|
|
144
|
-
var ref = String(token);
|
|
145
|
-
var outliers = [];
|
|
146
|
-
for (var i = 0; i < signatures.length; i++) {
|
|
147
|
-
var sig = signatures[i];
|
|
148
|
-
if (sig !== "" && sig !== ref) {
|
|
149
|
-
outliers.push(pageNames[i]);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return { reference: ref, source: "token", outliers: outliers };
|
|
153
|
-
}
|
|
154
|
-
// 2. All empty → source "none"
|
|
155
|
-
if (nonEmpty.length === 0) {
|
|
156
|
-
return { reference: null, source: "none", outliers: [] };
|
|
157
|
-
}
|
|
158
|
-
// 3. Modal inference
|
|
159
|
-
var modal = findModal(signatures);
|
|
160
|
-
if (modal !== null) {
|
|
161
|
-
// Clear modal: outliers are non-empty pages that differ
|
|
162
|
-
var outliers2 = [];
|
|
163
|
-
for (var j = 0; j < signatures.length; j++) {
|
|
164
|
-
if (signatures[j] !== "" && signatures[j] !== modal) {
|
|
165
|
-
outliers2.push(pageNames[j]);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return { reference: modal, source: "modal", outliers: outliers2 };
|
|
169
|
-
}
|
|
170
|
-
// 4. Tie (no modal): emit all non-empty differing pages as outliers.
|
|
171
|
-
// reference is null (can't declare canonical without a token), so source is
|
|
172
|
-
// "none" — "modal" always carries a non-null reference, keeping the two fields
|
|
173
|
-
// internally consistent for consumers.
|
|
174
|
-
var allOutliers = [];
|
|
175
|
-
for (var m = 0; m < signatures.length; m++) {
|
|
176
|
-
if (signatures[m] !== "") {
|
|
177
|
-
allOutliers.push(pageNames[m]);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return { reference: null, source: "none", outliers: allOutliers };
|
|
181
|
-
}
|
|
182
|
-
// ── Issue generation ──────────────────────────────────────────────────
|
|
183
|
-
function makeContainerIssue(outliers, reference) {
|
|
184
|
-
// Reference may be a numeric px width ("1152") or a class signature ("container-wide");
|
|
185
|
-
// only suffix "px" for the numeric form.
|
|
186
|
-
var refIsNumeric = reference !== null && /^\d+(?:\.\d+)?$/.test(reference);
|
|
187
|
-
var refStr = reference === null ? "(no modal — all values diverge)" : (refIsNumeric ? reference + "px" : reference);
|
|
188
|
-
var pageList = outliers.join(", ");
|
|
189
|
-
return {
|
|
190
|
-
severity: "warning",
|
|
191
|
-
rule: "consistency/container-width",
|
|
192
|
-
message: "Container-width inconsistency across pages. Reference: " +
|
|
193
|
-
refStr +
|
|
194
|
-
". Divergent page(s): " +
|
|
195
|
-
pageList +
|
|
196
|
-
".",
|
|
197
|
-
fix: "Align all pages to the same container token (" +
|
|
198
|
-
(reference === null ? "the project canonical width" : refStr) +
|
|
199
|
-
"). Use a shared layout wrapper so the container is defined once, not per-page."
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
function makeHeroIssue(outliers, reference) {
|
|
203
|
-
var refStr = reference !== null ? reference : "(no modal — all values diverge)";
|
|
204
|
-
var pageList = outliers.join(", ");
|
|
205
|
-
return {
|
|
206
|
-
severity: "warning",
|
|
207
|
-
rule: "consistency/hero-tier",
|
|
208
|
-
message: "Hero heading tier inconsistency across pages. Reference: " +
|
|
209
|
-
refStr +
|
|
210
|
-
". Divergent page(s): " +
|
|
211
|
-
pageList +
|
|
212
|
-
".",
|
|
213
|
-
fix: "Use the same hero heading class/size (" +
|
|
214
|
-
(reference !== null ? reference : "define a canonical tier") +
|
|
215
|
-
") for the top-level heading on every page. If a page intentionally uses a smaller heading, document the exception in the design system."
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Audit multiple pages for cross-page consistency of:
|
|
220
|
-
* - Content-container width (container_px / container_classes)
|
|
221
|
-
* - Hero heading tier (hero_size_px / hero_classes)
|
|
222
|
-
*
|
|
223
|
-
* Infers the canonical (modal) value from the corpus when no token is supplied.
|
|
224
|
-
* Pure — no I/O, no browser. Assumes pages.length >= 2.
|
|
225
|
-
*/
|
|
226
|
-
export function auditConsistency(pages, opts) {
|
|
227
|
-
var options = opts || {};
|
|
228
|
-
// Extract per-page data
|
|
229
|
-
var pageResults = pages.map(function (p) {
|
|
230
|
-
return extractPage(p.name, p.html);
|
|
231
|
-
});
|
|
232
|
-
var pageNames = pageResults.map(function (p) { return p.name; });
|
|
233
|
-
var containerSigs = pageResults.map(function (p) { return p.container.signature; });
|
|
234
|
-
var heroSigs = pageResults.map(function (p) { return p.hero.signature; });
|
|
235
|
-
// Consistency checks
|
|
236
|
-
var containerDim = checkDimension(pageNames, containerSigs, options.container_token);
|
|
237
|
-
var heroDim = checkDimension(pageNames, heroSigs, options.hero_token);
|
|
238
|
-
// Issues
|
|
239
|
-
var issues = [];
|
|
240
|
-
if (containerDim.outliers.length > 0) {
|
|
241
|
-
issues.push(makeContainerIssue(containerDim.outliers, containerDim.reference));
|
|
242
|
-
}
|
|
243
|
-
if (heroDim.outliers.length > 0) {
|
|
244
|
-
issues.push(makeHeroIssue(heroDim.outliers, heroDim.reference));
|
|
245
|
-
}
|
|
246
|
-
// Scoring
|
|
247
|
-
var failCount = (containerDim.outliers.length > 0 ? 1 : 0) +
|
|
248
|
-
(heroDim.outliers.length > 0 ? 1 : 0);
|
|
249
|
-
var score = Math.round(((2 - failCount) / 2) * 100);
|
|
250
|
-
var grade = failCount === 0 ? "A" : failCount === 1 ? "C" : "D";
|
|
251
|
-
// Summary
|
|
252
|
-
var summary;
|
|
253
|
-
if (failCount === 0) {
|
|
254
|
-
summary =
|
|
255
|
-
"All " +
|
|
256
|
-
pages.length +
|
|
257
|
-
" pages are consistent on container width and hero heading tier. Score: " +
|
|
258
|
-
score +
|
|
259
|
-
"/100 (A).";
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
var dims = [];
|
|
263
|
-
if (containerDim.outliers.length > 0)
|
|
264
|
-
dims.push("container width");
|
|
265
|
-
if (heroDim.outliers.length > 0)
|
|
266
|
-
dims.push("hero heading tier");
|
|
267
|
-
summary =
|
|
268
|
-
pages.length +
|
|
269
|
-
" pages audited. Inconsistency detected in: " +
|
|
270
|
-
dims.join(", ") +
|
|
271
|
-
". Score: " +
|
|
272
|
-
score +
|
|
273
|
-
"/100 (" +
|
|
274
|
-
grade +
|
|
275
|
-
").";
|
|
276
|
-
}
|
|
277
|
-
return {
|
|
278
|
-
page_count: pages.length,
|
|
279
|
-
pages: pageResults,
|
|
280
|
-
consistency: {
|
|
281
|
-
container: containerDim,
|
|
282
|
-
hero: heroDim
|
|
283
|
-
},
|
|
284
|
-
issues: issues,
|
|
285
|
-
score: score,
|
|
286
|
-
grade: grade,
|
|
287
|
-
summary: summary
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
//# sourceMappingURL=audit-consistency.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"audit-consistency.js","sourceRoot":"","sources":["../src/audit-consistency.ts"],"names":[],"mappings":"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"}
|
package/dist/layout-orphans.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export interface OrphanItem {
|
|
2
|
-
selector: string;
|
|
3
|
-
width: number;
|
|
4
|
-
height: number;
|
|
5
|
-
card_width: number;
|
|
6
|
-
ratio: number;
|
|
7
|
-
row_y: number;
|
|
8
|
-
}
|
|
9
|
-
export interface OrphanIssue {
|
|
10
|
-
severity: "warning";
|
|
11
|
-
rule: "layout/orphan-stretch";
|
|
12
|
-
message: string;
|
|
13
|
-
fix: string;
|
|
14
|
-
}
|
|
15
|
-
export interface OrphanStretchResult {
|
|
16
|
-
has_orphan: boolean;
|
|
17
|
-
card_width: number | null;
|
|
18
|
-
card_height: number | null;
|
|
19
|
-
card_count: number;
|
|
20
|
-
orphans: OrphanItem[];
|
|
21
|
-
issues: OrphanIssue[];
|
|
22
|
-
}
|
|
23
|
-
export interface OrphanElement {
|
|
24
|
-
selector: string;
|
|
25
|
-
rect: {
|
|
26
|
-
x: number;
|
|
27
|
-
y: number;
|
|
28
|
-
w: number;
|
|
29
|
-
h: number;
|
|
30
|
-
};
|
|
31
|
-
computed?: unknown;
|
|
32
|
-
}
|
|
33
|
-
export interface OrphanOpts {
|
|
34
|
-
widthRatio?: number;
|
|
35
|
-
}
|
|
36
|
-
export declare function detectOrphanStretch(elements: OrphanElement[], opts?: OrphanOpts): OrphanStretchResult;
|
package/dist/layout-orphans.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
// layout-orphans.ts
|
|
2
|
-
// Pure module — no I/O, no browser, no side effects.
|
|
3
|
-
// Exports detectOrphanStretch() for use by audit_layout.
|
|
4
|
-
function median(values) {
|
|
5
|
-
var sorted = values.slice().sort(function (a, b) { return a - b; });
|
|
6
|
-
var mid = Math.floor(sorted.length / 2);
|
|
7
|
-
if (sorted.length % 2 === 1) {
|
|
8
|
-
return sorted[mid];
|
|
9
|
-
}
|
|
10
|
-
return (sorted[mid - 1] + sorted[mid]) / 2;
|
|
11
|
-
}
|
|
12
|
-
export function detectOrphanStretch(elements, opts) {
|
|
13
|
-
var widthRatio = (opts && opts.widthRatio != null) ? opts.widthRatio : 1.5;
|
|
14
|
-
// Fresh object per call — never share a mutable singleton across returns.
|
|
15
|
-
function noCardResult() {
|
|
16
|
-
return {
|
|
17
|
-
has_orphan: false,
|
|
18
|
-
card_width: null,
|
|
19
|
-
card_height: null,
|
|
20
|
-
card_count: 0,
|
|
21
|
-
orphans: [],
|
|
22
|
-
issues: []
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
if (!elements || elements.length === 0) {
|
|
26
|
-
return noCardResult();
|
|
27
|
-
}
|
|
28
|
-
// Step 1: find the modal width cluster (count >= 3).
|
|
29
|
-
// Group rects whose widths are within ±12% of a representative.
|
|
30
|
-
var widthTol = 0.12;
|
|
31
|
-
var clusters = [];
|
|
32
|
-
for (var i = 0; i < elements.length; i++) {
|
|
33
|
-
var w = elements[i].rect.w;
|
|
34
|
-
var placed = false;
|
|
35
|
-
for (var c = 0; c < clusters.length; c++) {
|
|
36
|
-
var rep = clusters[c].rep;
|
|
37
|
-
if (Math.abs(w - rep) / rep <= widthTol) {
|
|
38
|
-
clusters[c].indices.push(i);
|
|
39
|
-
placed = true;
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (!placed) {
|
|
44
|
-
clusters.push({ rep: w, indices: [i] });
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// Find the largest cluster with count >= 3.
|
|
48
|
-
var bestCluster = null;
|
|
49
|
-
for (var k = 0; k < clusters.length; k++) {
|
|
50
|
-
if (clusters[k].indices.length >= 3) {
|
|
51
|
-
if (bestCluster === null || clusters[k].indices.length > bestCluster.indices.length) {
|
|
52
|
-
bestCluster = clusters[k];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (bestCluster === null) {
|
|
57
|
-
return noCardResult();
|
|
58
|
-
}
|
|
59
|
-
// W = median width of card group, H = median height of card group.
|
|
60
|
-
var cardWidths = bestCluster.indices.map(function (idx) { return elements[idx].rect.w; });
|
|
61
|
-
var cardHeights = bestCluster.indices.map(function (idx) { return elements[idx].rect.h; });
|
|
62
|
-
var W = median(cardWidths);
|
|
63
|
-
var H = median(cardHeights);
|
|
64
|
-
var cardCount = bestCluster.indices.length;
|
|
65
|
-
// Step 2: H-band = H ± 15%.
|
|
66
|
-
var hBandLo = H * (1 - 0.15);
|
|
67
|
-
var hBandHi = H * (1 + 0.15);
|
|
68
|
-
// Step 3: Find orphans.
|
|
69
|
-
// An orphan: height in H-band AND width >= widthRatio * W,
|
|
70
|
-
// EXCLUDING elements within ±12% of W (those are cards).
|
|
71
|
-
var orphans = [];
|
|
72
|
-
for (var j = 0; j < elements.length; j++) {
|
|
73
|
-
var el = elements[j];
|
|
74
|
-
var ew = el.rect.w;
|
|
75
|
-
var eh = el.rect.h;
|
|
76
|
-
// Must be in the H-band.
|
|
77
|
-
if (eh < hBandLo || eh > hBandHi) {
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
// Must be wide enough to be an orphan.
|
|
81
|
-
if (ew < widthRatio * W) {
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
// Exclude elements within ±12% of W (they are cards, not orphans).
|
|
85
|
-
if (Math.abs(ew - W) / W <= widthTol) {
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
orphans.push({
|
|
89
|
-
selector: el.selector,
|
|
90
|
-
width: ew,
|
|
91
|
-
height: eh,
|
|
92
|
-
card_width: W,
|
|
93
|
-
ratio: Number((ew / W).toFixed(2)),
|
|
94
|
-
row_y: el.rect.y
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
// Sort orphans by rect.y descending (last-row orphan first).
|
|
98
|
-
orphans.sort(function (a, b) { return b.row_y - a.row_y; });
|
|
99
|
-
// Build issues: one per orphan.
|
|
100
|
-
var issues = orphans.map(function (o) {
|
|
101
|
-
var message = o.selector + " spans " + o.width + "px — " + o.ratio + "× the " + W + "px card width (lonely last-row orphan).";
|
|
102
|
-
var fix = "Use grid-template-columns: repeat(auto-fill, " + W + "px) (auto-FILL, not auto-fit) or cap item max-width:" + W + "px so a lone final-row card stays card-width.";
|
|
103
|
-
return {
|
|
104
|
-
severity: "warning",
|
|
105
|
-
rule: "layout/orphan-stretch",
|
|
106
|
-
message: message,
|
|
107
|
-
fix: fix
|
|
108
|
-
};
|
|
109
|
-
});
|
|
110
|
-
return {
|
|
111
|
-
has_orphan: orphans.length > 0,
|
|
112
|
-
card_width: W,
|
|
113
|
-
card_height: H,
|
|
114
|
-
card_count: cardCount,
|
|
115
|
-
orphans: orphans,
|
|
116
|
-
issues: issues
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
//# sourceMappingURL=layout-orphans.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"layout-orphans.js","sourceRoot":"","sources":["../src/layout-orphans.ts"],"names":[],"mappings":"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"}
|
package/dist/score-page.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* score-page.ts — per-category 0–10 design scorer built on the shared audit_page rule engine.
|
|
3
|
-
*
|
|
4
|
-
* Reuses runPageChecks verbatim — no fork, no edit to page-checks.ts.
|
|
5
|
-
* Returns per-category scores (7 assessed categories), the same overall 0–100 / grade
|
|
6
|
-
* audit_page produces, the weakest category, and an honest list of categories Raven
|
|
7
|
-
* does not mechanically assess.
|
|
8
|
-
*/
|
|
9
|
-
export type ScoreGrade = "A" | "B" | "C" | "D";
|
|
10
|
-
export type CategoryScore = {
|
|
11
|
-
category: string;
|
|
12
|
-
label: string;
|
|
13
|
-
score: number;
|
|
14
|
-
errors: number;
|
|
15
|
-
warnings: number;
|
|
16
|
-
rationale: string;
|
|
17
|
-
};
|
|
18
|
-
export type OverallScore = {
|
|
19
|
-
score: number;
|
|
20
|
-
grade: ScoreGrade;
|
|
21
|
-
summary: string;
|
|
22
|
-
};
|
|
23
|
-
export type NotAssessed = {
|
|
24
|
-
categories: string[];
|
|
25
|
-
note: string;
|
|
26
|
-
};
|
|
27
|
-
export type ScorePageResult = {
|
|
28
|
-
overall: OverallScore;
|
|
29
|
-
categories: CategoryScore[];
|
|
30
|
-
weakest_category: string;
|
|
31
|
-
not_assessed: NotAssessed;
|
|
32
|
-
};
|
|
33
|
-
export declare function scorePage(html: string, opts?: {
|
|
34
|
-
strict?: boolean;
|
|
35
|
-
containerMaxWidth?: number;
|
|
36
|
-
}): ScorePageResult;
|
package/dist/score-page.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* score-page.ts — per-category 0–10 design scorer built on the shared audit_page rule engine.
|
|
3
|
-
*
|
|
4
|
-
* Reuses runPageChecks verbatim — no fork, no edit to page-checks.ts.
|
|
5
|
-
* Returns per-category scores (7 assessed categories), the same overall 0–100 / grade
|
|
6
|
-
* audit_page produces, the weakest category, and an honest list of categories Raven
|
|
7
|
-
* does not mechanically assess.
|
|
8
|
-
*/
|
|
9
|
-
import { runPageChecks } from "./page-checks.js";
|
|
10
|
-
// ── Canonical category definitions ───────────────────────────────────────────
|
|
11
|
-
const CATEGORIES = [
|
|
12
|
-
{ key: "structure", label: "Structure" },
|
|
13
|
-
{ key: "typography", label: "Typography" },
|
|
14
|
-
{ key: "color", label: "Color & palette" },
|
|
15
|
-
{ key: "spacing", label: "Spacing & rhythm" },
|
|
16
|
-
{ key: "a11y", label: "Accessibility" },
|
|
17
|
-
{ key: "responsive", label: "Responsive layout" },
|
|
18
|
-
{ key: "tokens", label: "Design tokens" },
|
|
19
|
-
];
|
|
20
|
-
const NOT_ASSESSED_CATEGORIES = ["brand", "conversion", "motion"];
|
|
21
|
-
const NOT_ASSESSED_NOTE = "Brand voice, conversion effectiveness, and motion design are not mechanically assessed by " +
|
|
22
|
-
"Raven's rule engine. Use evaluate_design for brand and conversion judgment, and " +
|
|
23
|
-
"score_creative for creative / motion quality.";
|
|
24
|
-
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
25
|
-
function clamp(value, min, max) {
|
|
26
|
-
return Math.max(min, Math.min(max, value));
|
|
27
|
-
}
|
|
28
|
-
function pluralise(count, singular, plural) {
|
|
29
|
-
return count === 1 ? singular : plural;
|
|
30
|
-
}
|
|
31
|
-
function buildRationale(errors, warnings) {
|
|
32
|
-
if (errors === 0 && warnings === 0)
|
|
33
|
-
return "all checks passed";
|
|
34
|
-
const parts = [];
|
|
35
|
-
if (errors > 0)
|
|
36
|
-
parts.push(errors + " " + pluralise(errors, "error", "errors"));
|
|
37
|
-
if (warnings > 0)
|
|
38
|
-
parts.push(warnings + " " + pluralise(warnings, "warning", "warnings"));
|
|
39
|
-
return parts.join(", ");
|
|
40
|
-
}
|
|
41
|
-
// ── Core scorer ───────────────────────────────────────────────────────────────
|
|
42
|
-
export function scorePage(html, opts) {
|
|
43
|
-
const strict = opts && opts.strict === true;
|
|
44
|
-
const containerMaxWidth = opts ? opts.containerMaxWidth : undefined;
|
|
45
|
-
const { passes, issues } = runPageChecks(html, { containerMaxWidth });
|
|
46
|
-
const errors = issues.filter(i => i.severity === "error");
|
|
47
|
-
const warnings = issues.filter(i => i.severity === "warning");
|
|
48
|
-
// ── Overall (byte-identical to audit_page arithmetic) ─────────────────────
|
|
49
|
-
const totalChecks = passes.length + issues.length;
|
|
50
|
-
const failCount = strict ? issues.length : errors.length;
|
|
51
|
-
const overallScore = totalChecks > 0 ? Math.round(((totalChecks - failCount) / totalChecks) * 100) : 100;
|
|
52
|
-
const grade = failCount === 0 ? "A" :
|
|
53
|
-
failCount <= 2 ? "B" :
|
|
54
|
-
failCount <= 4 ? "C" : "D";
|
|
55
|
-
// ── Per-category ──────────────────────────────────────────────────────────
|
|
56
|
-
const categories = CATEGORIES.map(({ key, label }) => {
|
|
57
|
-
const prefix = key + "/";
|
|
58
|
-
const catErrors = issues.filter(i => i.severity === "error" && i.rule.startsWith(prefix));
|
|
59
|
-
const catWarnings = issues.filter(i => i.severity === "warning" && i.rule.startsWith(prefix));
|
|
60
|
-
const eCount = catErrors.length;
|
|
61
|
-
const wCount = catWarnings.length;
|
|
62
|
-
const penalty = eCount * 4 + wCount * 2;
|
|
63
|
-
const score = clamp(10 - penalty, 0, 10);
|
|
64
|
-
return {
|
|
65
|
-
category: key,
|
|
66
|
-
label,
|
|
67
|
-
score,
|
|
68
|
-
errors: eCount,
|
|
69
|
-
warnings: wCount,
|
|
70
|
-
rationale: buildRationale(eCount, wCount),
|
|
71
|
-
};
|
|
72
|
-
});
|
|
73
|
-
// ── Weakest category (first in canonical order on ties) ───────────────────
|
|
74
|
-
let weakestScore = Infinity;
|
|
75
|
-
let weakestKey = CATEGORIES[0].key;
|
|
76
|
-
for (const cat of categories) {
|
|
77
|
-
if (cat.score < weakestScore) {
|
|
78
|
-
weakestScore = cat.score;
|
|
79
|
-
weakestKey = cat.category;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// ── Overall summary ───────────────────────────────────────────────────────
|
|
83
|
-
const weakestLabel = categories.find(c => c.category === weakestKey)?.label ?? weakestKey;
|
|
84
|
-
const summary = `Overall ${overallScore}/100 (${grade}) — weakest: ${weakestLabel}`;
|
|
85
|
-
return {
|
|
86
|
-
overall: { score: overallScore, grade, summary },
|
|
87
|
-
categories,
|
|
88
|
-
weakest_category: weakestKey,
|
|
89
|
-
not_assessed: {
|
|
90
|
-
categories: NOT_ASSESSED_CATEGORIES,
|
|
91
|
-
note: NOT_ASSESSED_NOTE,
|
|
92
|
-
},
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
//# sourceMappingURL=score-page.js.map
|
package/dist/score-page.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"score-page.js","sourceRoot":"","sources":["../src/score-page.ts"],"names":[],"mappings":"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"}
|
package/dist/video-playback.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* video-playback.ts — Video playback audit module for audit_video_playback tool.
|
|
3
|
-
* Pure classifier + Playwright-backed page observer.
|
|
4
|
-
* No new npm dependencies required.
|
|
5
|
-
*/
|
|
6
|
-
import { CaptureUnavailableError } from "./capture.js";
|
|
7
|
-
export { CaptureUnavailableError };
|
|
8
|
-
export type VideoObservation = {
|
|
9
|
-
selector: string;
|
|
10
|
-
hasSource: boolean;
|
|
11
|
-
readyState: number;
|
|
12
|
-
networkState: number;
|
|
13
|
-
errorCode: number;
|
|
14
|
-
paused: boolean;
|
|
15
|
-
autoplayBlocked: boolean;
|
|
16
|
-
currentTimeStart: number;
|
|
17
|
-
currentTimeEnd: number;
|
|
18
|
-
};
|
|
19
|
-
export type VideoClassification = {
|
|
20
|
-
selector: string;
|
|
21
|
-
state: "playing" | "paused" | "stalled" | "empty" | "error";
|
|
22
|
-
reason: string;
|
|
23
|
-
advanced: boolean;
|
|
24
|
-
};
|
|
25
|
-
export type VideoRow = VideoClassification & {
|
|
26
|
-
readyState: number;
|
|
27
|
-
errorCode: number;
|
|
28
|
-
paused: boolean;
|
|
29
|
-
currentTimeStart: number;
|
|
30
|
-
currentTimeEnd: number;
|
|
31
|
-
};
|
|
32
|
-
export type VideoPlaybackResult = {
|
|
33
|
-
url: string | null;
|
|
34
|
-
total_videos: number;
|
|
35
|
-
rows: VideoRow[];
|
|
36
|
-
playing_count: number;
|
|
37
|
-
not_playing_count: number;
|
|
38
|
-
not_playing: VideoRow[];
|
|
39
|
-
summary: string;
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Classify a single VideoObservation into a state+reason pair.
|
|
43
|
-
* First-match-wins order per SPEC:
|
|
44
|
-
* 1. error — errorCode > 0
|
|
45
|
-
* 2. empty — hasSource === false OR networkState === 3
|
|
46
|
-
* 3. playing — currentTimeEnd - currentTimeStart > 1e-3 AND paused === false
|
|
47
|
-
* 4. paused — readyState >= 3 AND not advancing
|
|
48
|
-
* 5. stalled — fallthrough
|
|
49
|
-
*/
|
|
50
|
-
export declare function classifyVideoPlayback(obs: VideoObservation): VideoClassification;
|
|
51
|
-
export declare function auditVideoPlaybackSnapshot(observations: VideoObservation[], url?: string | null): VideoPlaybackResult;
|
|
52
|
-
/**
|
|
53
|
-
* Render a URL in headless Chromium, locate every <video>, observe whether
|
|
54
|
-
* playback actually advances (samples currentTime before/after a play attempt),
|
|
55
|
-
* classify each clip, and return a VideoPlaybackResult.
|
|
56
|
-
*
|
|
57
|
-
* Throws CaptureUnavailableError when chromium is unavailable.
|
|
58
|
-
*/
|
|
59
|
-
export declare function auditVideoPlaybackUrl(url: string, opts?: {
|
|
60
|
-
observeMs?: number;
|
|
61
|
-
}): Promise<VideoPlaybackResult>;
|
package/dist/video-playback.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* video-playback.ts — Video playback audit module for audit_video_playback tool.
|
|
3
|
-
* Pure classifier + Playwright-backed page observer.
|
|
4
|
-
* No new npm dependencies required.
|
|
5
|
-
*/
|
|
6
|
-
import { CaptureUnavailableError } from "./capture.js";
|
|
7
|
-
export { CaptureUnavailableError };
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
// Pure classifier — exported for tests, no I/O
|
|
10
|
-
// ---------------------------------------------------------------------------
|
|
11
|
-
/**
|
|
12
|
-
* Classify a single VideoObservation into a state+reason pair.
|
|
13
|
-
* First-match-wins order per SPEC:
|
|
14
|
-
* 1. error — errorCode > 0
|
|
15
|
-
* 2. empty — hasSource === false OR networkState === 3
|
|
16
|
-
* 3. playing — currentTimeEnd - currentTimeStart > 1e-3 AND paused === false
|
|
17
|
-
* 4. paused — readyState >= 3 AND not advancing
|
|
18
|
-
* 5. stalled — fallthrough
|
|
19
|
-
*/
|
|
20
|
-
export function classifyVideoPlayback(obs) {
|
|
21
|
-
const advanced = obs.currentTimeEnd - obs.currentTimeStart > 1e-3;
|
|
22
|
-
// 1. error
|
|
23
|
-
if (obs.errorCode > 0) {
|
|
24
|
-
const reasonMap = {
|
|
25
|
-
1: "aborted",
|
|
26
|
-
2: "network-error",
|
|
27
|
-
3: "decode-error",
|
|
28
|
-
4: "src-not-supported",
|
|
29
|
-
};
|
|
30
|
-
const reason = reasonMap[obs.errorCode] ?? "unknown-error";
|
|
31
|
-
return { selector: obs.selector, state: "error", reason, advanced };
|
|
32
|
-
}
|
|
33
|
-
// 2. empty
|
|
34
|
-
if (!obs.hasSource || obs.networkState === 3) {
|
|
35
|
-
return { selector: obs.selector, state: "empty", reason: "empty-src", advanced };
|
|
36
|
-
}
|
|
37
|
-
// 3. playing
|
|
38
|
-
if (advanced && !obs.paused) {
|
|
39
|
-
return { selector: obs.selector, state: "playing", reason: "advancing", advanced };
|
|
40
|
-
}
|
|
41
|
-
// 4. paused
|
|
42
|
-
if (obs.readyState >= 3) {
|
|
43
|
-
const reason = obs.autoplayBlocked ? "autoplay-blocked" : "paused";
|
|
44
|
-
return { selector: obs.selector, state: "paused", reason, advanced };
|
|
45
|
-
}
|
|
46
|
-
// 5. stalled (fallthrough)
|
|
47
|
-
return { selector: obs.selector, state: "stalled", reason: "buffering-or-stalled", advanced };
|
|
48
|
-
}
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
|
-
// Pure aggregator — exported for tests, no I/O. Single source of truth for the
|
|
51
|
-
// VideoPlaybackResult shape, shared by the browser path and the dom_snapshot
|
|
52
|
-
// handler (mirrors contrast.ts's auditContrastSnapshot).
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
export function auditVideoPlaybackSnapshot(observations, url = null) {
|
|
55
|
-
const rows = observations.map((obs) => {
|
|
56
|
-
const classification = classifyVideoPlayback(obs);
|
|
57
|
-
return {
|
|
58
|
-
...classification,
|
|
59
|
-
readyState: obs.readyState,
|
|
60
|
-
errorCode: obs.errorCode,
|
|
61
|
-
paused: obs.paused,
|
|
62
|
-
currentTimeStart: obs.currentTimeStart,
|
|
63
|
-
currentTimeEnd: obs.currentTimeEnd,
|
|
64
|
-
};
|
|
65
|
-
});
|
|
66
|
-
const total_videos = rows.length;
|
|
67
|
-
const playing_count = rows.filter((r) => r.state === "playing").length;
|
|
68
|
-
const not_playing = rows.filter((r) => r.state !== "playing");
|
|
69
|
-
const not_playing_count = not_playing.length;
|
|
70
|
-
const summary = total_videos === 0
|
|
71
|
-
? "No <video> elements found."
|
|
72
|
-
: `${playing_count}/${total_videos} video(s) playing; ${not_playing_count} not playing (${not_playing.map((r) => r.state).join(", ") || "none"}).`;
|
|
73
|
-
return {
|
|
74
|
-
url,
|
|
75
|
-
total_videos,
|
|
76
|
-
rows,
|
|
77
|
-
playing_count,
|
|
78
|
-
not_playing_count,
|
|
79
|
-
not_playing,
|
|
80
|
-
summary,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
// URL audit (Playwright)
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
/**
|
|
87
|
-
* Render a URL in headless Chromium, locate every <video>, observe whether
|
|
88
|
-
* playback actually advances (samples currentTime before/after a play attempt),
|
|
89
|
-
* classify each clip, and return a VideoPlaybackResult.
|
|
90
|
-
*
|
|
91
|
-
* Throws CaptureUnavailableError when chromium is unavailable.
|
|
92
|
-
*/
|
|
93
|
-
export async function auditVideoPlaybackUrl(url, opts) {
|
|
94
|
-
let chromium;
|
|
95
|
-
try {
|
|
96
|
-
const pw = await import("playwright");
|
|
97
|
-
chromium = pw.chromium;
|
|
98
|
-
}
|
|
99
|
-
catch {
|
|
100
|
-
throw new CaptureUnavailableError("Playwright chromium not available. Run: npx playwright install chromium");
|
|
101
|
-
}
|
|
102
|
-
const observeMs = opts?.observeMs ?? 1000;
|
|
103
|
-
let browser = null;
|
|
104
|
-
try {
|
|
105
|
-
try {
|
|
106
|
-
browser = await chromium.launch({ headless: true });
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
throw new CaptureUnavailableError("Playwright chromium not available. Run: npx playwright install chromium");
|
|
110
|
-
}
|
|
111
|
-
const page = await browser.newPage();
|
|
112
|
-
await page.goto(url, { waitUntil: "load" });
|
|
113
|
-
// Step 1: collect initial state + currentTimeStart, then call play() for each video
|
|
114
|
-
const initialData = await page.evaluate(() => {
|
|
115
|
-
const videos = Array.from(document.querySelectorAll("video"));
|
|
116
|
-
return videos.map((el, k) => {
|
|
117
|
-
// Build a stable-ish selector
|
|
118
|
-
const id = el.getAttribute("id");
|
|
119
|
-
const cls = el.className ? "." + el.className.trim().split(/\s+/).join(".") : "";
|
|
120
|
-
const selector = id ? `#${id}` : `video:nth-of-type(${k + 1})${cls}`;
|
|
121
|
-
const hasSource = (el.currentSrc !== undefined && el.currentSrc !== "") ||
|
|
122
|
-
el.getAttribute("src") !== null ||
|
|
123
|
-
el.querySelector("source") !== null;
|
|
124
|
-
return {
|
|
125
|
-
selector,
|
|
126
|
-
hasSource,
|
|
127
|
-
readyState: el.readyState,
|
|
128
|
-
networkState: el.networkState,
|
|
129
|
-
errorCode: el.error ? el.error.code : 0,
|
|
130
|
-
paused: el.paused,
|
|
131
|
-
autoplayBlocked: false,
|
|
132
|
-
currentTimeStart: el.currentTime,
|
|
133
|
-
};
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
// Step 2: attempt play() for each video, detect NotAllowedError
|
|
137
|
-
const autoplayBlocked = [];
|
|
138
|
-
const videoCount = initialData.length;
|
|
139
|
-
for (let k = 0; k < videoCount; k++) {
|
|
140
|
-
const blocked = await page.evaluate((idx) => {
|
|
141
|
-
const videos = Array.from(document.querySelectorAll("video"));
|
|
142
|
-
const el = videos[idx];
|
|
143
|
-
if (!el)
|
|
144
|
-
return false;
|
|
145
|
-
return el.play().then(() => false, (err) => {
|
|
146
|
-
return (err.name === "NotAllowedError" ||
|
|
147
|
-
(err.message !== undefined &&
|
|
148
|
-
err.message.toLowerCase().indexOf("notallowed") !== -1));
|
|
149
|
-
});
|
|
150
|
-
}, k);
|
|
151
|
-
autoplayBlocked.push(blocked);
|
|
152
|
-
}
|
|
153
|
-
// Step 3: wait observeMs
|
|
154
|
-
await page.waitForTimeout(observeMs);
|
|
155
|
-
const finalData = await page.evaluate(() => {
|
|
156
|
-
const videos = Array.from(document.querySelectorAll("video"));
|
|
157
|
-
return videos.map((el) => {
|
|
158
|
-
const hasSource = (el.currentSrc !== undefined && el.currentSrc !== "") ||
|
|
159
|
-
el.getAttribute("src") !== null ||
|
|
160
|
-
el.querySelector("source") !== null;
|
|
161
|
-
return {
|
|
162
|
-
readyState: el.readyState,
|
|
163
|
-
networkState: el.networkState,
|
|
164
|
-
errorCode: el.error ? el.error.code : 0,
|
|
165
|
-
paused: el.paused,
|
|
166
|
-
currentTimeEnd: el.currentTime,
|
|
167
|
-
hasSource,
|
|
168
|
-
};
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
// Step 5: assemble observations and classify in Node (pure classifier, not in page)
|
|
172
|
-
const observations = initialData.map((init, k) => {
|
|
173
|
-
const fin = finalData[k] ?? {
|
|
174
|
-
readyState: init.readyState,
|
|
175
|
-
networkState: init.networkState,
|
|
176
|
-
errorCode: init.errorCode,
|
|
177
|
-
paused: init.paused,
|
|
178
|
-
currentTimeEnd: init.currentTimeStart,
|
|
179
|
-
hasSource: init.hasSource,
|
|
180
|
-
};
|
|
181
|
-
return {
|
|
182
|
-
selector: init.selector,
|
|
183
|
-
hasSource: fin.hasSource,
|
|
184
|
-
readyState: fin.readyState,
|
|
185
|
-
networkState: fin.networkState,
|
|
186
|
-
errorCode: fin.errorCode,
|
|
187
|
-
paused: fin.paused,
|
|
188
|
-
autoplayBlocked: autoplayBlocked[k] ?? false,
|
|
189
|
-
currentTimeStart: init.currentTimeStart,
|
|
190
|
-
currentTimeEnd: fin.currentTimeEnd,
|
|
191
|
-
};
|
|
192
|
-
});
|
|
193
|
-
return auditVideoPlaybackSnapshot(observations, url);
|
|
194
|
-
}
|
|
195
|
-
finally {
|
|
196
|
-
if (browser) {
|
|
197
|
-
await browser.close();
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
//# sourceMappingURL=video-playback.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"video-playback.js","sourceRoot":"","sources":["../src/video-playback.ts"],"names":[],"mappings":"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"}
|