Skip to content

Commit 9feedaf

Browse files
NiklasMerzclaude
andauthored
feat: add Servo & WPE from results repo (#67)
* feat: add servo and WPE from our support repository * show versions * servo description * use raw bcd collector result for WPE --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 926bac3 commit 9feedaf

6 files changed

Lines changed: 141 additions & 19 deletions

File tree

_clients/servo.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
platforms: [android]
3+
display_order: 5
4+
webview: true
5+
---
6+
Servo aims to empower developers with a lightweight, high-performance alternative for embedding web technologies in applications.

_clients/wpe_minibrowser.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
platforms: [linux]
3+
display_order: 4
4+
webview: true
5+
---
6+
WPE is an official port of WebKit for embedded and low-consumption devices.

_data/nicenames.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ family:
55
webview2: "WebView2"
66
chrome_android: "Chrome Browser"
77
safari_ios: "Safari Browser"
8+
wpe_minibrowser: "WPE MiniBrowser"
9+
servo: "Servo"
810
platform:
911
ios: "iOS"
1012
android: "Android"
1113
windows: "Windows"
1214
macos: "macOS"
15+
linux: "Linux"
1316
support:
1417
supported: "Supported"
1518
mitigated: "Partial support"

_js/_settings.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,14 @@ class Settings {
2727
const settingsString = this.getLocalStorage();
2828
if (settingsString && settingsString !== '') {
2929
const settings = settingsString.split('&');
30+
// Collect the client names that have an explicit saved state.
31+
// Clients added after the settings were last saved will not be in this
32+
// set and should keep their HTML defaults (checked if webview: true).
33+
const savedNames = new Set(settings.map(s => s.split('=')[0]));
3034
this.panel.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
31-
checkbox.checked = false;
35+
if (savedNames.has(checkbox.name)) {
36+
checkbox.checked = false;
37+
}
3238
});
3339
if (settings.length > 0) {
3440
settings.forEach(setting => {

_layouts/feature.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ <h3 class="data-family-name">
8383
{% endif %}
8484
</span>
8585
</h3>
86+
{% assign bcd-test-meta = site.data.bcd_test_meta[family-key] %}
8687
<div class="data-client-list">
8788
{% if family-values != nil %}
8889
{% for platform in family-values %}
@@ -117,7 +118,14 @@ <h4 class="data-platform-name">
117118
{% assign stat-class-name = '' -%}
118119
{% endcase %}
119120
<div class="data-version {{ stat-class-name }}">
120-
<span class="data-version-number">{{ version-key }}</span>
121+
{% if bcd-test-meta %}
122+
<a class="data-version-number" href="{{ bcd-test-meta.source_url }}"
123+
title="Support data from automated BCD compatibility tests"
124+
target="_blank" rel="noopener noreferrer">{{ version-key }}</a>
125+
{% else %}
126+
<span class="data-version-number"
127+
{% if site.data.bcd_version %}title="From BCD package version {{ site.data.bcd_version }}"{% endif %}>{{ version-key }}</span>
128+
{% endif %}
121129
<span class="data-version-badge {{ stat-class-name }}"
122130
aria-label="{{ site.data.nicenames.support[stat-class-name] }}"></span>
123131
{% if version-notes.size > 0 %}

_plugins/generated_features.rb

Lines changed: 110 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
require 'httparty'
22
require 'json'
3+
require 'time'
34

45
module Generated
56
class FeaturesGenerator < Jekyll::Generator
@@ -85,14 +86,94 @@ def getVersions(feature, platform)
8586
}
8687
end
8788

88-
def generate_bcd_from_section(site, section, timestamp, category, appended_title = "")
89-
section.keys.each do |title|
89+
def parse_bcd_collector_results(parsed)
90+
# Raw mdn-bcd-collector output: results is keyed by test URL → array of
91+
# { exposure, name, result } entries. We only record Window-exposed results.
92+
bcd_map = {}
93+
return bcd_map unless parsed.key?('results')
94+
parsed['results'].each do |_url, tests|
95+
next unless tests.kind_of?(Array)
96+
tests.each do |test|
97+
next unless test['exposure'] == 'Window'
98+
key = test['name']
99+
next if bcd_map.key?(key)
100+
bcd_map[key] = test['result'] == true ? 'y' : 'n'
101+
end
102+
end
103+
bcd_map
104+
end
105+
106+
def fetch_wpe_minibrowser_results
107+
distilled_url = "https://wpewebkit.org/wptreport-distilled-data/bcd_results-wpewebkit_minibrowser-nightly-tot.json"
108+
distilled = JSON.parse(HTTParty.get(distilled_url).body)
109+
metadata = distilled['metadata'] || {}
110+
source_urls = metadata['x_source_results_urls'] || []
111+
collector_url = source_urls.first
112+
return nil unless collector_url
113+
collector = JSON.parse(HTTParty.get(collector_url).body)
114+
version = if metadata['testrun_timestamp_end']
115+
Time.at(metadata['testrun_timestamp_end']).utc.strftime('%Y-%m-%d')
116+
else
117+
'latest'
118+
end
119+
{
120+
'results' => parse_bcd_collector_results(collector),
121+
'version' => version,
122+
'source_url' => 'https://wpewebkit.org/wpt-status/?src=BCD',
123+
}
124+
rescue => e
125+
Jekyll.logger.warn "webview-bcd-results:", "Failed to fetch WPE results: #{e.message}"
126+
nil
127+
end
128+
129+
def extract_version_from_results(file_name)
130+
# Date embedded in filename (e.g. latest-servo-2026-03-27.json)
131+
file_name =~ /(\d{4}-\d{2}-\d{2})/ ? $1 : nil
132+
end
133+
134+
def fetch_latest_webview_results
135+
results = {}
136+
137+
# WPE MiniBrowser: fetch the distilled data published by the WPE project,
138+
# then download the raw mdn-bcd-collector results it points to.
139+
wpe = fetch_wpe_minibrowser_results
140+
results['wpe_minibrowser'] = wpe if wpe
141+
142+
# Servo and any other latest-* files come from the WebView-CG repo.
143+
api_url = "https://api.github.com/repos/WebView-CG/webview-bcd-results/contents/results"
144+
response = HTTParty.get(api_url, headers: { "User-Agent" => "CanIWebView-build" })
145+
files = JSON.parse(response.body)
146+
files.each do |file|
147+
name = file['name']
148+
next unless name.start_with?('latest-servo')
149+
begin
150+
content = HTTParty.get(file['download_url']).body
151+
parsed = JSON.parse(content)
152+
version = extract_version_from_results(name) || 'latest'
153+
results['servo'] = {
154+
'results' => parse_bcd_collector_results(parsed),
155+
'version' => version,
156+
'source_url' => file['html_url'],
157+
}
158+
rescue => e
159+
Jekyll.logger.warn "webview-bcd-results:", "Failed to process #{name}: #{e.message}"
160+
end
161+
end
162+
results
163+
rescue => e
164+
Jekyll.logger.warn "webview-bcd-results:", "Failed to fetch latest results: #{e.message}"
165+
{}
166+
end
167+
168+
def generate_bcd_from_section(site, section, timestamp, category, appended_title = "", bcd_prefix = "", latest_results = {})
169+
section.keys.each do |key|
90170
# We skip potential special keys since we can iterate over sub sections
91-
next unless title.index("__") != 0
171+
next unless key.index("__") != 0
92172

93-
feature = section[title]
173+
feature = section[key]
94174

95-
title = "#{appended_title}#{title}"
175+
bcd_key = bcd_prefix.empty? ? key : "#{bcd_prefix}.#{key}"
176+
title = "#{appended_title}#{key}"
96177
slug = "mdn-#{title.downcase.strip.gsub('-', '').gsub(/[\_|\s]/, '-').gsub(':', '')}"
97178
path = site.in_source_dir("_generated_features/#{slug}.md")
98179
doc = Jekyll::Document.new(path, {
@@ -114,7 +195,7 @@ def generate_bcd_from_section(site, section, timestamp, category, appended_title
114195
impl_urls = getImplUrls(feature)
115196
doc.data['links'] = links.merge(impl_urls)
116197
doc.data['has_impl_urls'] = !impl_urls.empty?
117-
doc.data['stats'] = {
198+
stats = {
118199
"wkwebview" => {
119200
"macos" => {
120201
"*" => "u"
@@ -136,42 +217,54 @@ def generate_bcd_from_section(site, section, timestamp, category, appended_title
136217
"ios" => getVersions(feature, "safari_ios")
137218
},
138219
}
220+
latest_results.each do |client, data|
221+
platform = client == "wpe_minibrowser" ? "linux" : "android"
222+
support = data['results'].fetch(bcd_key, "u")
223+
version = data['version']
224+
stats[client] = { platform => { version => support } }
225+
end
226+
doc.data['stats'] = stats
139227

140228
site.collections['generated_features'].docs << doc
141229
end
142230
end
143231

144232
def generate_bcd(site)
145-
version = File.read("bcd_version")
233+
version = File.read("bcd_version").strip
146234
bcd = HTTParty.get("http://unpkg.com/@mdn/browser-compat-data@#{version}/data.json").body
147235
parsed_bcd = JSON.parse(bcd)
148236

149237
timestamp = parsed_bcd['__meta']['timestamp']
238+
site.data['bcd_version'] = version
239+
240+
latest_results = fetch_latest_webview_results()
241+
242+
site.data['bcd_test_meta'] = latest_results
150243

151244
generate_bcd_from_section(site, parsed_bcd['api'],
152-
timestamp, "js")
245+
timestamp, "js", "", "api", latest_results)
153246
generate_bcd_from_section(site, parsed_bcd['javascript']['builtins'],
154-
timestamp, "js", "JavaScript built-in: ")
247+
timestamp, "js", "JavaScript built-in: ", "javascript.builtins", latest_results)
155248
generate_bcd_from_section(site, parsed_bcd['html']['elements'],
156-
timestamp, "html", "HTML element: ")
249+
timestamp, "html", "HTML element: ", "html.elements", latest_results)
157250
generate_bcd_from_section(site, parsed_bcd['html']['global_attributes'],
158-
timestamp, "html", "HTML attribute: ")
251+
timestamp, "html", "HTML attribute: ", "html.global_attributes", latest_results)
159252
generate_bcd_from_section(site, parsed_bcd['manifests']['webapp'],
160-
timestamp, "html", "HTML manifest: ")
253+
timestamp, "html", "HTML manifest: ", "manifests.webapp", latest_results)
161254
generate_bcd_from_section(site, parsed_bcd['css']['selectors'],
162-
timestamp, "css", "CSS selector: ")
255+
timestamp, "css", "CSS selector: ", "css.selectors", latest_results)
163256
generate_bcd_from_section(site, parsed_bcd['css']['properties'],
164-
timestamp, "css", "CSS property: ")
257+
timestamp, "css", "CSS property: ", "css.properties", latest_results)
165258
generate_bcd_from_section(site, parsed_bcd['http']['headers'],
166-
timestamp, "http", "HTTP header: ")
259+
timestamp, "http", "HTTP header: ", "http.headers", latest_results)
167260
generate_bcd_from_section(site, parsed_bcd['http']['status'],
168-
timestamp, "http", "HTTP status code: ")
261+
timestamp, "http", "HTTP status code: ", "http.status", latest_results)
169262

170263
# The css types can have sub fields so we iterate over these and then
171264
# generate sections.
172265
parsed_bcd['css']['types'].keys.each do |type|
173266
generate_bcd_from_section(site, parsed_bcd['css']['types'][type],
174-
timestamp, "css", "CSS type: #{type}: ")
267+
timestamp, "css", "CSS type: #{type}: ", "css.types.#{type}", latest_results)
175268
end
176269
end
177270

0 commit comments

Comments
 (0)