@@ -27,6 +27,7 @@ import {
2727 concat ,
2828 defer ,
2929 from ,
30+ identity ,
3031 map ,
3132 merge ,
3233 mergeMap ,
@@ -112,6 +113,75 @@ function minsvg(data: string): string {
112113 return result . data
113114}
114115
116+ /**
117+ * Return a path with POSIX style separators
118+ *
119+ * The default function assumes UNIX system, so it just returns the path.
120+ *
121+ * @param p - string path
122+ * @returns String path
123+ */
124+ let assurePosixSep = function ( p : string ) : string {
125+ return p
126+ } ;
127+
128+ /**
129+ * Return a path with POSIX style separators
130+ *
131+ * The Windows variant of this function replaces the separator with regex.
132+ *
133+ * @param p - string path
134+ * @returns String path
135+ */
136+ function assurePosixSepWin ( p : string ) : string {
137+ return p . replace ( winSepRegex , path . posix . sep )
138+ } ;
139+
140+ const winSepRegex = new RegExp ( `\\${ path . win32 . sep } ` , "g" ) ;
141+
142+ if ( path . sep === path . win32 . sep ) {
143+ assurePosixSep = assurePosixSepWin ;
144+ }
145+
146+ /**
147+ * Compare two path strings to decide on the order
148+ *
149+ * On Windows the default order of paths containing `_` from the resolve function
150+ * is different than on macOS. This function restores the order to the usual.
151+ * Implementation adapted based on https://t.ly/VJp78
152+ *
153+ * Note: The paths should have no extension like .svg, just the name. Otherwise
154+ * it won't check the compare.startsWith(reference) properly.
155+ *
156+ * @param reference Left string to compare
157+ * @param compare Right string to compare against
158+ * @returns Number for the sort function to define the order
159+ */
160+ function sortOrderForWindows ( reference : string , compare : string ) : number {
161+ reference = reference . toLowerCase ( ) ;
162+ compare = compare . toLowerCase ( ) ;
163+
164+ const length = Math . min ( reference . length , compare . length ) ;
165+
166+ for ( let i = 0 ; i < length ; i ++ ) {
167+ const leftChar = reference [ i ] ;
168+ const rightChar = compare [ i ] ;
169+
170+ if ( leftChar !== rightChar )
171+ return customAlphabet . indexOf ( leftChar ) - customAlphabet . indexOf ( rightChar ) ;
172+ }
173+
174+ if ( reference . length !== compare . length ) {
175+ if ( compare . startsWith ( reference ) && compare [ reference . length ] === "-" )
176+ return 1 ;
177+ return reference . length - compare . length ;
178+ }
179+
180+ return 0 ;
181+ }
182+
183+ const customAlphabet : string = "_,-./0123456789abcdefghijklmnopqrstuvwxyz" ;
184+
115185/* ----------------------------------------------------------------------------
116186 * Tasks
117187 * ------------------------------------------------------------------------- */
@@ -187,7 +257,7 @@ const sources$ = copyAll("**/*.py", {
187257const stylesheets$ = resolve ( "**/[!_]*.scss" , { cwd : "src" } )
188258 . pipe (
189259 mergeMap ( file => zip (
190- of ( ext ( file , ".css" ) . replace ( / ( o v e r r i d e s | t e m p l a t e s ) \/ / , "" ) ) ,
260+ of ( ext ( file , ".css" ) . replace ( new RegExp ( `( overrides|templates)\\ ${ path . sep } ` ) , "" ) ) ,
191261 transformStyle ( {
192262 from : `src/${ file } ` ,
193263 to : ext ( `${ base } /${ file } ` , ".css" )
@@ -199,7 +269,7 @@ const stylesheets$ = resolve("**/[!_]*.scss", { cwd: "src" })
199269const javascripts$ = resolve ( "**/{custom,bundle,search}.ts" , { cwd : "src" } )
200270 . pipe (
201271 mergeMap ( file => zip (
202- of ( ext ( file , ".js" ) . replace ( / ( o v e r r i d e s | t e m p l a t e s ) \/ / , "" ) ) ,
272+ of ( ext ( file , ".js" ) . replace ( new RegExp ( `( overrides|templates)\\ ${ path . sep } ` ) , "" ) ) ,
203273 transformScript ( {
204274 from : `src/${ file } ` ,
205275 to : ext ( `${ base } /${ file } ` , ".js" )
@@ -229,10 +299,10 @@ const manifest$ = merge(
229299 . pipe (
230300 scan ( ( prev , mapping ) => (
231301 mapping . reduce ( ( next , [ key , value ] ) => (
232- next . set ( key , value . replace (
233- new RegExp ( `${ base } \\/(overrides|templates)\\/ ` ) ,
302+ next . set ( assurePosixSep ( key ) , assurePosixSep ( value . replace (
303+ new RegExp ( `${ base } \\/(overrides|templates)\\${ path . sep } ` ) ,
234304 ""
235- ) )
305+ ) ) )
236306 ) , prev )
237307 ) , new Map < string , string > ( ) ) ,
238308 )
@@ -291,9 +361,15 @@ const icons$ = defer(() => resolve("**/*.svg", {
291361} ) )
292362 . pipe (
293363 reduce ( ( index , file ) => index . set (
294- file . replace ( / \. s v g $ / , "" ) . replace ( / \/ / g, "-" ) ,
295- file
296- ) , new Map < string , string > ( ) )
364+ file . replace ( / \. s v g $ / , "" ) . replace ( new RegExp ( `\\${ path . sep } ` , "g" ) , "-" ) ,
365+ assurePosixSep ( file )
366+ ) , new Map < string , string > ( ) ) ,
367+ // The icons are stored in the index file, and the output needs to be OS
368+ // agnostic. Some icons contain the `_` character, which has different order
369+ // in the glob output on Windows.
370+ ( path . sep === path . win32 . sep ) ? map ( icons => new Map (
371+ [ ...icons ] . sort ( ( a , b ) => sortOrderForWindows ( a [ 0 ] , b [ 0 ] ) )
372+ ) ) : identity
297373 )
298374
299375/* Compute emoji mappings (based on Twemoji) */
@@ -372,7 +448,7 @@ const schema$ = merge(
372448 "reference/icons-emojis/#search"
373449 ] . join ( "/" ) ,
374450 "type" : "string" ,
375- "enum" : icons . map ( icon => icon . replace ( ".svg" , "" ) )
451+ "enum" : icons . map ( icon => assurePosixSep ( icon . replace ( ".svg" , "" ) ) )
376452 } ) ) ,
377453 switchMap ( data => write (
378454 "docs/schema/assets/icons.json" ,
0 commit comments