@@ -104,6 +104,46 @@ function getCPUArchLabel(name) {
104104 }
105105}
106106
107+ function getPreliminaryPageData ( ) {
108+ const identifier = getIdentifierFromSiteLocation ( )
109+ if ( identifier ) {
110+ let data = { identifier : identifier }
111+ if ( identifier . startsWith ( 'I' ) || identifier . startsWith ( 'Y' ) ) {
112+ data . label = identifier
113+ } else if ( identifier . startsWith ( 'S-' ) || identifier . startsWith ( 'R-' ) ) {
114+ data . label = identifier . substring ( 2 , identifier . indexOf ( '-' , 2 ) )
115+ const versionEndIndex = Math . max ( data . label . indexOf ( 'M' ) , data . label . indexOf ( 'RC' ) )
116+ const version = versionEndIndex < 0 ? data . label : data . label . substring ( 0 , versionEndIndex )
117+ data . release = version . split ( '.' ) . length === 2 ? ( version + '.0' ) : version
118+ data . releaseShort = data . release . substring ( 0 , data . release . lastIndexOf ( '.' ) )
119+ } else {
120+ throw new Error ( `Unexpected identifier: ${ identifier } ` )
121+ }
122+ if ( ! identifier . startsWith ( 'Y' ) ) { // Y-build's adapt their 'kind' to the targeted java version, which is therefore not constant
123+ data . kind = 'Integration'
124+ }
125+ if ( _dataGenerator ) {
126+ data = _dataGenerator ( data )
127+ }
128+ Object . keys ( data ) . forEach ( k => data [ k ] == undefined && delete data [ k ] ) ;
129+ return data
130+ }
131+ return null
132+ }
133+
134+ function getIdentifierFromSiteLocation ( ) {
135+ if ( window . location . hostname === 'download.eclipse.org' ) {
136+ const pathname = window . location . pathname
137+ for ( const prefix of [ '/eclipse/downloads/drops4/' , '/equinox/drops/' ] ) {
138+ if ( pathname . startsWith ( prefix ) ) {
139+ const idEndingSlash = pathname . indexOf ( '/' , prefix . length )
140+ return pathname . substring ( prefix . length , idEndingSlash > - 1 ? idEndingSlash : pathname . length )
141+ }
142+ }
143+ }
144+ return null
145+ }
146+
107147const BUILD_DATE_FORMAT = new Intl . DateTimeFormat ( 'en-GB' , {
108148 timeZone : 'UTC' ,
109149 year : 'numeric' ,
@@ -173,8 +213,10 @@ function fetchAllJSON(urls) {
173213}
174214
175215let _pageData = null
216+ let _dataGenerator = null
176217
177218function loadPageData ( dataPath , dataGenerator = null ) {
219+ _dataGenerator = dataGenerator
178220 _pageData = fetch ( dataPath ) . then ( res => res . json ( ) )
179221 if ( dataGenerator ) {
180222 _pageData = _pageData . then ( dataGenerator )
@@ -200,12 +242,20 @@ function generate() {
200242 }
201243
202244 const generatedBody = generateBody ( ) ;
245+ // To reduce flickering, early resolve variables that can be derived from the build-drop's folder name
246+ const preliminaryData = _pageData ? getPreliminaryPageData ( ) : null
247+ if ( preliminaryData ) {
248+ resolveDataReferences ( generatedBody , preliminaryData , true )
249+ }
203250 document . body . replaceChildren ( generatedBody ) ;
204251
205252 generateTOCItems ( document . body ) // assume no headers (for the TOC) are generated dynamically
206253
207254 if ( _pageData ) {
208255 _pageData . then ( data => {
256+ if ( preliminaryData ) {
257+ verifyDataConsistency ( preliminaryData , data )
258+ }
209259 const mainElement = document . body . querySelector ( 'main' )
210260 const contentMain = mainElement . querySelector ( 'main' ) // This is the main element of the calling html file
211261 resolveDataReferences ( document , data )
@@ -234,27 +284,47 @@ function generateTOCItems(mainElement) {
234284
235285const dataReferencePattern = / \$ { (?< path > [ \w \- \. ] + ) } / g
236286
237- function resolveDataReferences ( contextElement , contextData ) {
287+ function resolveDataReferences ( contextElement , contextData , lenient = false ) {
238288 const dataElements = Array . from ( contextElement . getElementsByClassName ( 'data-ref' ) )
239289 for ( const element of dataElements ) {
240- element . classList . remove ( 'data-ref' ) // Prevent multiple processing in subsequent passes with different context (therefore a copy is created from the list)
241- element . outerHTML = element . outerHTML . replaceAll ( dataReferencePattern , ( _match , pathGroup , _offset , _string ) => {
242- return getValue ( contextData , pathGroup )
290+ const resolved = element . outerHTML . replaceAll ( dataReferencePattern , ( match , pathGroup , _offset , _string ) => {
291+ return getValue ( contextData , pathGroup , lenient ? match : undefined )
243292 } )
293+ element . outerHTML = resolved
294+ dataReferencePattern . lastIndex = 0 // reset lastIndex as RegExp.prototype.test() is stateful. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test
295+ if ( ! lenient || ! dataReferencePattern . test ( resolved ) ) {
296+ // Prevent multiple processing in subsequent passes with different context (if no variables are contained anymore)
297+ element . classList . remove ( 'data-ref' )
298+ }
244299 }
245300}
246301
247- function getValue ( data , path ) {
302+ function getValue ( data , path , lenienceDefaultValue = undefined ) {
248303 let value = data
249304 for ( const key of path . split ( '.' ) ) {
250305 if ( ! value . hasOwnProperty ( key ) ) {
306+ if ( lenienceDefaultValue ) {
307+ return lenienceDefaultValue // just skip absent variables
308+ }
251309 throw new Error ( `Key '${ key } ' not found in ${ JSON . stringify ( value ) } ` )
252310 }
253311 value = value [ key ]
254312 }
255313 return value ;
256314}
257315
316+ function verifyDataConsistency ( preliminaryData , data ) {
317+ for ( const key in preliminaryData ) {
318+ if ( data [ key ] !== preliminaryData [ key ] ) {
319+ const msg = `Prelininary value of key '${ key } ' differes from loaded data.
320+ preliminary - ${ preliminaryData [ key ] } ,
321+ loaded data - ${ data [ key ] } `
322+ logException ( msg , msg )
323+ throw new Error ( msg )
324+ }
325+ }
326+ }
327+
258328function logException ( message , loggedObject ) {
259329 document . body . prepend ( toElement ( `<p>Failed to generate content: <b style="color: FireBrick">${ message } </b></p>` ) ) ;
260330 console . log ( loggedObject ) ;
0 commit comments