-
{{ version-key }}
+ {% if bcd-test-meta %}
+
{{ version-key }}
+ {% else %}
+
{{ version-key }}
+ {% endif %}
{% if version-notes.size > 0 %}
diff --git a/_plugins/generated_features.rb b/_plugins/generated_features.rb
index 792e497..31381dd 100644
--- a/_plugins/generated_features.rb
+++ b/_plugins/generated_features.rb
@@ -1,5 +1,6 @@
require 'httparty'
require 'json'
+require 'time'
module Generated
class FeaturesGenerator < Jekyll::Generator
@@ -85,14 +86,94 @@ def getVersions(feature, platform)
}
end
- def generate_bcd_from_section(site, section, timestamp, category, appended_title = "")
- section.keys.each do |title|
+ def parse_bcd_collector_results(parsed)
+ # Raw mdn-bcd-collector output: results is keyed by test URL → array of
+ # { exposure, name, result } entries. We only record Window-exposed results.
+ bcd_map = {}
+ return bcd_map unless parsed.key?('results')
+ parsed['results'].each do |_url, tests|
+ next unless tests.kind_of?(Array)
+ tests.each do |test|
+ next unless test['exposure'] == 'Window'
+ key = test['name']
+ next if bcd_map.key?(key)
+ bcd_map[key] = test['result'] == true ? 'y' : 'n'
+ end
+ end
+ bcd_map
+ end
+
+ def fetch_wpe_minibrowser_results
+ distilled_url = "https://wpewebkit.org/wptreport-distilled-data/bcd_results-wpewebkit_minibrowser-nightly-tot.json"
+ distilled = JSON.parse(HTTParty.get(distilled_url).body)
+ metadata = distilled['metadata'] || {}
+ source_urls = metadata['x_source_results_urls'] || []
+ collector_url = source_urls.first
+ return nil unless collector_url
+ collector = JSON.parse(HTTParty.get(collector_url).body)
+ version = if metadata['testrun_timestamp_end']
+ Time.at(metadata['testrun_timestamp_end']).utc.strftime('%Y-%m-%d')
+ else
+ 'latest'
+ end
+ {
+ 'results' => parse_bcd_collector_results(collector),
+ 'version' => version,
+ 'source_url' => 'https://wpewebkit.org/wpt-status/?src=BCD',
+ }
+ rescue => e
+ Jekyll.logger.warn "webview-bcd-results:", "Failed to fetch WPE results: #{e.message}"
+ nil
+ end
+
+ def extract_version_from_results(file_name)
+ # Date embedded in filename (e.g. latest-servo-2026-03-27.json)
+ file_name =~ /(\d{4}-\d{2}-\d{2})/ ? $1 : nil
+ end
+
+ def fetch_latest_webview_results
+ results = {}
+
+ # WPE MiniBrowser: fetch the distilled data published by the WPE project,
+ # then download the raw mdn-bcd-collector results it points to.
+ wpe = fetch_wpe_minibrowser_results
+ results['wpe_minibrowser'] = wpe if wpe
+
+ # Servo and any other latest-* files come from the WebView-CG repo.
+ api_url = "https://api.github.com/repos/WebView-CG/webview-bcd-results/contents/results"
+ response = HTTParty.get(api_url, headers: { "User-Agent" => "CanIWebView-build" })
+ files = JSON.parse(response.body)
+ files.each do |file|
+ name = file['name']
+ next unless name.start_with?('latest-servo')
+ begin
+ content = HTTParty.get(file['download_url']).body
+ parsed = JSON.parse(content)
+ version = extract_version_from_results(name) || 'latest'
+ results['servo'] = {
+ 'results' => parse_bcd_collector_results(parsed),
+ 'version' => version,
+ 'source_url' => file['html_url'],
+ }
+ rescue => e
+ Jekyll.logger.warn "webview-bcd-results:", "Failed to process #{name}: #{e.message}"
+ end
+ end
+ results
+ rescue => e
+ Jekyll.logger.warn "webview-bcd-results:", "Failed to fetch latest results: #{e.message}"
+ {}
+ end
+
+ def generate_bcd_from_section(site, section, timestamp, category, appended_title = "", bcd_prefix = "", latest_results = {})
+ section.keys.each do |key|
# We skip potential special keys since we can iterate over sub sections
- next unless title.index("__") != 0
+ next unless key.index("__") != 0
- feature = section[title]
+ feature = section[key]
- title = "#{appended_title}#{title}"
+ bcd_key = bcd_prefix.empty? ? key : "#{bcd_prefix}.#{key}"
+ title = "#{appended_title}#{key}"
slug = "mdn-#{title.downcase.strip.gsub('-', '').gsub(/[\_|\s]/, '-').gsub(':', '')}"
path = site.in_source_dir("_generated_features/#{slug}.md")
doc = Jekyll::Document.new(path, {
@@ -114,7 +195,7 @@ def generate_bcd_from_section(site, section, timestamp, category, appended_title
impl_urls = getImplUrls(feature)
doc.data['links'] = links.merge(impl_urls)
doc.data['has_impl_urls'] = !impl_urls.empty?
- doc.data['stats'] = {
+ stats = {
"wkwebview" => {
"macos" => {
"*" => "u"
@@ -136,42 +217,54 @@ def generate_bcd_from_section(site, section, timestamp, category, appended_title
"ios" => getVersions(feature, "safari_ios")
},
}
+ latest_results.each do |client, data|
+ platform = client == "wpe_minibrowser" ? "linux" : "android"
+ support = data['results'].fetch(bcd_key, "u")
+ version = data['version']
+ stats[client] = { platform => { version => support } }
+ end
+ doc.data['stats'] = stats
site.collections['generated_features'].docs << doc
end
end
def generate_bcd(site)
- version = File.read("bcd_version")
+ version = File.read("bcd_version").strip
bcd = HTTParty.get("http://unpkg.com/@mdn/browser-compat-data@#{version}/data.json").body
parsed_bcd = JSON.parse(bcd)
timestamp = parsed_bcd['__meta']['timestamp']
+ site.data['bcd_version'] = version
+
+ latest_results = fetch_latest_webview_results()
+
+ site.data['bcd_test_meta'] = latest_results
generate_bcd_from_section(site, parsed_bcd['api'],
- timestamp, "js")
+ timestamp, "js", "", "api", latest_results)
generate_bcd_from_section(site, parsed_bcd['javascript']['builtins'],
- timestamp, "js", "JavaScript built-in: ")
+ timestamp, "js", "JavaScript built-in: ", "javascript.builtins", latest_results)
generate_bcd_from_section(site, parsed_bcd['html']['elements'],
- timestamp, "html", "HTML element: ")
+ timestamp, "html", "HTML element: ", "html.elements", latest_results)
generate_bcd_from_section(site, parsed_bcd['html']['global_attributes'],
- timestamp, "html", "HTML attribute: ")
+ timestamp, "html", "HTML attribute: ", "html.global_attributes", latest_results)
generate_bcd_from_section(site, parsed_bcd['manifests']['webapp'],
- timestamp, "html", "HTML manifest: ")
+ timestamp, "html", "HTML manifest: ", "manifests.webapp", latest_results)
generate_bcd_from_section(site, parsed_bcd['css']['selectors'],
- timestamp, "css", "CSS selector: ")
+ timestamp, "css", "CSS selector: ", "css.selectors", latest_results)
generate_bcd_from_section(site, parsed_bcd['css']['properties'],
- timestamp, "css", "CSS property: ")
+ timestamp, "css", "CSS property: ", "css.properties", latest_results)
generate_bcd_from_section(site, parsed_bcd['http']['headers'],
- timestamp, "http", "HTTP header: ")
+ timestamp, "http", "HTTP header: ", "http.headers", latest_results)
generate_bcd_from_section(site, parsed_bcd['http']['status'],
- timestamp, "http", "HTTP status code: ")
+ timestamp, "http", "HTTP status code: ", "http.status", latest_results)
# The css types can have sub fields so we iterate over these and then
# generate sections.
parsed_bcd['css']['types'].keys.each do |type|
generate_bcd_from_section(site, parsed_bcd['css']['types'][type],
- timestamp, "css", "CSS type: #{type}: ")
+ timestamp, "css", "CSS type: #{type}: ", "css.types.#{type}", latest_results)
end
end