33const asciidoctor = require ( 'asciidoctor.js' ) ( )
44const fs = require ( 'fs-extra' )
55const handlebars = require ( 'handlebars' )
6+ const iconPacks = {
7+ fas : ( ( ) => {
8+ try {
9+ return require ( '@fortawesome/pro-solid-svg-icons' )
10+ } catch ( e ) {
11+ return require ( '@fortawesome/free-solid-svg-icons' )
12+ }
13+ } ) ( ) ,
14+ far : ( ( ) => {
15+ try {
16+ return require ( '@fortawesome/pro-regular-svg-icons' )
17+ } catch ( e ) {
18+ return require ( '@fortawesome/free-regular-svg-icons' )
19+ }
20+ } ) ( ) ,
21+ fab : require ( '@fortawesome/free-brands-svg-icons' ) ,
22+ }
23+ iconPacks . fa = iconPacks . fas
24+ const iconShims = require ( '@fortawesome/fontawesome-free/js/v4-shims' ) . reduce ( ( accum , it ) => {
25+ accum [ it [ 0 ] ] = [ it [ 1 ] || 'fas' , it [ 2 ] || it [ 0 ] ]
26+ return accum
27+ } , { } )
628const { obj : map } = require ( 'through2' )
729const merge = require ( 'merge-stream' )
830const ospath = require ( 'path' )
@@ -21,73 +43,83 @@ module.exports = (src, previewSrc, previewDest, sink = () => map()) => (done) =>
2143 ) ,
2244 ] )
2345 . then ( ( [ baseUiModel , { layouts } ] ) => [ { ...baseUiModel , env : process . env } , layouts ] )
24- . then ( ( [ baseUiModel , layouts ] ) =>
46+ . then ( ( [ baseUiModel , layouts , iconDefs = new Map ( ) ] ) =>
2547 vfs
2648 . src ( '**/*.adoc' , { base : previewSrc , cwd : previewSrc } )
2749 . pipe (
28- map ( ( file , enc , next ) => {
29- const siteRootPath = path . relative ( ospath . dirname ( file . path ) , ospath . resolve ( previewSrc ) )
30- const uiModel = { ...baseUiModel }
31- uiModel . siteRootPath = siteRootPath
32- uiModel . siteRootUrl = path . join ( siteRootPath , 'index.html' )
33- uiModel . uiRootPath = path . join ( siteRootPath , '_' )
34- if ( file . stem === '404' ) {
35- uiModel . page = { layout : '404' , title : 'Page Not Found' }
36- } else {
37- const pageModel = ( uiModel . page = { ...uiModel . page } )
38- const doc = asciidoctor . load ( file . contents , { safe : 'safe' , attributes : ASCIIDOC_ATTRIBUTES } )
39- const attributes = doc . getAttributes ( )
40- pageModel . layout = doc . getAttribute ( 'page-layout' , 'default' )
41- pageModel . title = doc . getDocumentTitle ( )
42- pageModel . url = '/' + file . relative . slice ( 0 , - 5 ) + '.html'
43- if ( file . stem === 'home' ) pageModel . home = true
44- const componentName = doc . getAttribute ( 'page-component-name' , pageModel . src . component )
45- const versionString = doc . getAttribute (
46- 'page-version' ,
47- doc . hasAttribute ( 'page-component-name' ) ? undefined : pageModel . src . version
48- )
49- let component
50- let componentVersion
51- if ( componentName ) {
52- component = pageModel . component = uiModel . site . components [ componentName ]
53- componentVersion = pageModel . componentVersion = versionString
54- ? component . versions . find ( ( { version } ) => version === versionString )
55- : component . latest
50+ map (
51+ ( file , enc , next ) => {
52+ const siteRootPath = path . relative ( ospath . dirname ( file . path ) , ospath . resolve ( previewSrc ) )
53+ const uiModel = {
54+ ...baseUiModel ,
55+ preview : true ,
56+ siteRootPath,
57+ siteRootUrl : path . join ( siteRootPath , 'index.html' ) ,
58+ uiRootPath : path . join ( siteRootPath , '_' ) ,
59+ }
60+ if ( file . stem === '404' ) {
61+ uiModel . page = { layout : '404' , title : 'Page Not Found' }
5662 } else {
57- component = pageModel . component = Object . values ( uiModel . site . components ) [ 0 ]
58- componentVersion = pageModel . componentVersion = component . latest
63+ const pageModel = ( uiModel . page = { ...uiModel . page } )
64+ const doc = asciidoctor . load ( file . contents , { safe : 'safe' , attributes : ASCIIDOC_ATTRIBUTES } )
65+ const attributes = doc . getAttributes ( )
66+ pageModel . layout = doc . getAttribute ( 'page-layout' , 'default' )
67+ pageModel . title = doc . getDocumentTitle ( )
68+ pageModel . url = '/' + file . relative . slice ( 0 , - 5 ) + '.html'
69+ if ( file . stem === 'home' ) pageModel . home = true
70+ const componentName = doc . getAttribute ( 'page-component-name' , pageModel . src . component )
71+ const versionString = doc . getAttribute (
72+ 'page-version' ,
73+ doc . hasAttribute ( 'page-component-name' ) ? undefined : pageModel . src . version
74+ )
75+ let component
76+ let componentVersion
77+ if ( componentName ) {
78+ component = pageModel . component = uiModel . site . components [ componentName ]
79+ componentVersion = pageModel . componentVersion = versionString
80+ ? component . versions . find ( ( { version } ) => version === versionString )
81+ : component . latest
82+ } else {
83+ component = pageModel . component = Object . values ( uiModel . site . components ) [ 0 ]
84+ componentVersion = pageModel . componentVersion = component . latest
85+ }
86+ pageModel . module = 'ROOT'
87+ pageModel . relativeSrcPath = file . relative
88+ pageModel . version = componentVersion . version
89+ pageModel . displayVersion = componentVersion . displayVersion
90+ pageModel . editUrl = pageModel . origin . editUrlPattern . replace ( '%s' , file . relative )
91+ pageModel . navigation = componentVersion . navigation || [ ]
92+ pageModel . breadcrumbs = findNavPath ( pageModel . url , pageModel . navigation )
93+ if ( pageModel . component . versions . length > 1 ) {
94+ pageModel . versions = pageModel . component . versions . map (
95+ ( { version, displayVersion, url } , idx , arr ) => {
96+ const pageVersion = { version, displayVersion : displayVersion || version , url }
97+ if ( version === component . latest . version ) pageVersion . latest = true
98+ if ( idx === arr . length - 1 ) {
99+ delete pageVersion . url
100+ pageVersion . missing = true
101+ }
102+ return pageVersion
103+ }
104+ )
105+ }
106+ pageModel . attributes = Object . entries ( { ...attributes , ...componentVersion . asciidoc . attributes } )
107+ . filter ( ( [ name , val ] ) => name . startsWith ( 'page-' ) )
108+ . reduce ( ( accum , [ name , val ] ) => ( { ...accum , [ name . substr ( 5 ) ] : val } ) , { } )
109+ pageModel . contents = Buffer . from ( doc . convert ( ) )
59110 }
60- pageModel . module = 'ROOT'
61- pageModel . relativeSrcPath = file . relative
62- pageModel . version = componentVersion . version
63- pageModel . displayVersion = componentVersion . displayVersion
64- pageModel . editUrl = pageModel . origin . editUrlPattern . replace ( '%s' , file . relative )
65- pageModel . navigation = componentVersion . navigation || [ ]
66- pageModel . breadcrumbs = findNavPath ( pageModel . url , pageModel . navigation )
67- if ( pageModel . component . versions . length > 1 ) {
68- pageModel . versions = pageModel . component . versions . map ( ( { version, displayVersion, url } , idx , arr ) => {
69- const pageVersion = { version, displayVersion : displayVersion || version , url }
70- if ( version === component . latest . version ) pageVersion . latest = true
71- if ( idx === arr . length - 1 ) {
72- delete pageVersion . url
73- pageVersion . missing = true
74- }
75- return pageVersion
76- } )
111+ file . extname = '.html'
112+ try {
113+ file . contents = Buffer . from ( layouts . get ( uiModel . page . layout ) ( uiModel ) )
114+ registerIconDefs ( iconDefs , file )
115+ next ( null , file )
116+ } catch ( e ) {
117+ next ( transformHandlebarsError ( e , uiModel . page . layout ) )
77118 }
78- pageModel . attributes = Object . entries ( { ...attributes , ...componentVersion . asciidoc . attributes } )
79- . filter ( ( [ name , val ] ) => name . startsWith ( 'page-' ) )
80- . reduce ( ( accum , [ name , val ] ) => ( { ...accum , [ name . substr ( 5 ) ] : val } ) , { } )
81- pageModel . contents = Buffer . from ( doc . convert ( ) )
82- }
83- file . extname = '.html'
84- try {
85- file . contents = Buffer . from ( layouts . get ( uiModel . page . layout ) ( uiModel ) )
86- next ( null , file )
87- } catch ( e ) {
88- next ( transformHandlebarsError ( e , uiModel . page . layout ) )
89- }
90- } )
119+ } ,
120+ // NOTE parallel build overwrites default fontawesome-icon-defs.js, so we must use an alternate path
121+ ( ) => writeIconDefs ( iconDefs , ospath . join ( previewDest , 'fontawesome-icon-defs.js' ) )
122+ )
91123 )
92124 . pipe ( vfs . dest ( previewDest ) )
93125 . on ( 'error' , ( e ) => done )
@@ -183,6 +215,37 @@ function findNavPath (currentUrl, node = [], current_path = [], root = true) {
183215 if ( root ) return [ ]
184216}
185217
218+ function registerIconDefs ( iconDefs , file ) {
219+ const contents = file . contents
220+ if ( ! contents . includes ( '<i class="fa' ) ) return
221+ const stringContents = contents . toString ( )
222+ const iconNames = stringContents . match ( / < i c l a s s = " f a [ b r s ] ? f a - [ ^ " ] + / g) . map ( ( it ) => it . substr ( 10 ) . replace ( 'fa-' , '' ) )
223+ if ( ! iconNames . length ) return
224+ ; [ ...new Set ( iconNames ) ] . reduce ( ( accum , iconKey ) => {
225+ if ( ! accum . has ( iconKey ) ) {
226+ const [ iconPrefix , iconName ] = iconKey . split ( ' ' ) . slice ( 0 , 2 )
227+ let iconDef = ( iconPacks [ iconPrefix ] || { } ) [ 'fa' + camelCase ( iconName ) ]
228+ if ( iconDef ) {
229+ return accum . set ( iconKey , { ...iconDef , prefix : iconPrefix } )
230+ } else if ( iconPrefix === 'fa' ) {
231+ const [ realIconPrefix , realIconName ] = iconShims [ iconName ] || [ ]
232+ if (
233+ ! accum . has ( ( iconKey = `${ realIconPrefix } ${ realIconName } ` ) ) &&
234+ realIconName &&
235+ ( iconDef = ( iconPacks [ realIconPrefix ] || { } ) [ 'fa' + camelCase ( realIconName ) ] )
236+ ) {
237+ return accum . set ( iconKey , { ...iconDef , prefix : realIconPrefix } )
238+ }
239+ }
240+ }
241+ return accum
242+ } , iconDefs )
243+ }
244+
245+ async function writeIconDefs ( iconDefs , to ) {
246+ return fs . writeFile ( to , `window.FontAwesomeIconDefs = ${ JSON . stringify ( [ ...iconDefs . values ( ) ] ) } \n` , 'utf8' )
247+ }
248+
186249function relativize ( url ) {
187250 return url ? ( url . charAt ( ) === '#' ? url : url . slice ( 1 ) ) : '#'
188251}
@@ -211,3 +274,9 @@ function toPromise (stream) {
211274 . on ( 'finish' , ( ) => resolve ( data ) )
212275 )
213276}
277+
278+ function camelCase ( str ) {
279+ return str . replace ( / (?: ^ | - ) ( .) / g, function ( _ , l ) {
280+ return l . toUpperCase ( )
281+ } )
282+ }
0 commit comments