11require 'httparty'
22require 'json'
3+ require 'time'
34
45module 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