-
-
Notifications
You must be signed in to change notification settings - Fork 213
Expand file tree
/
Copy pathtransition_properties.sql
More file actions
135 lines (120 loc) · 3.51 KB
/
Copy pathtransition_properties.sql
File metadata and controls
135 lines (120 loc) · 3.51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#standardSQL
CREATE TEMPORARY FUNCTION getTransitionProperties(css STRING)
RETURNS ARRAY<STRING>
LANGUAGE js
OPTIONS (library = "gs://httparchive/lib/css-utils.js")
AS '''
try {
function compute(ast) {
let ret = {
properties: new Set(),
animation_names: new Set(),
timing_functions: {},
// to calculate avg, median etc in the SQL. All durations are normalized to ms.
durations: {}
};
const easings = /step(s|-start|-end)|ease((-in)?(-out)?)|linear|cubic-bezier/;
function parseDuration(duration) {
let num = parseFloat(duration);
let unit = duration.endsWith("ms")? "ms" : "s";
return unit === "s"? num * 1000 : num;
}
walkDeclarations(ast, ({property, value}) => {
if (property === "transition-property") {
value.split(/\\s*,\\s*/).forEach(p => ret.properties.add(p));
}
else if (property.endsWith("tion-timing-functon")) {
let names = value.match(/^([a-z-]+)/g);
for (let name of names) {
if (/^(jump(-start|-end|-none|-both)|start|end)$/.test(name)) {
// Drop steps() params
continue;
}
incrementByKey(ret.timing_functions, name);
}
}
else if (property.endsWith("-duration")) {
incrementByKey(ret.durations, parseDuration(value));
}
else if (property === "transition" || property === "animation") {
// Extract property name and timing function
let keywords = (value.match(/(^|\\s)(d|r|[cr]?x|[cr]?y|[a-z-]{3,})(?=\\s|$|\\()/g) || []);
for (let keyword of keywords) {
keyword = keyword.trim();
if (/^(jump(-start|-end|-none|-both)|start|end)$/.test(keyword)) {
// Drop steps() params
continue;
}
if (easings.test(keyword)) {
incrementByKey(ret.timing_functions, keyword);
}
else if (property === "transition") {
ret.properties.add(keyword);
}
}
// Extract durations
for (let times of value.matchAll(/(?<duration>[\\d.]+m?s)(\\s+(?<delay>[\\d.]+m?s))?/g)) {
incrementByKey(ret.durations, parseDuration(times.groups.duration));
}
}
}, {
properties: /^(transition|animation)(?=$|-)/g,
not: {
values: ["inherit", "initial", "unset", "revert", /\bvar\\(--/]
}
})
// Animation names
walkRules(ast, rule => {
ret.animation_names.add(rule.name);
}, {type: "keyframes"});
ret.properties = [...new Set(ret.properties)];
ret.animation_names = [...ret.animation_names];
ret.durations = sortObject(ret.durations);
ret.timing_functions = sortObject(ret.timing_functions);
return ret;
}
const ast = JSON.parse(css);
let transitions = compute(ast);
return Array.from(transitions.properties);
} catch (e) {
return [];
}
''';
SELECT
client,
property,
COUNT(DISTINCT page) AS pages,
total,
COUNT(DISTINCT page) / total AS pct
FROM (
SELECT DISTINCT
client,
page,
property
FROM
`httparchive.almanac.parsed_css`,
UNNEST(getTransitionProperties(css)) AS property
WHERE
date = '2022-07-01' AND -- noqa: CV09
# Limit the size of the CSS to avoid OOM crashes.
LENGTH(css) < 0.1 * 1024 * 1024 AND
property IS NOT NULL
)
JOIN (
SELECT
_TABLE_SUFFIX AS client,
COUNT(0) AS total
FROM
`httparchive.summary_pages.2022_07_01_*` -- noqa: CV09
GROUP BY
client
)
USING (client)
GROUP BY
client,
property,
total
HAVING
pages >= 100
ORDER BY
pct DESC