1+ 'use strict' ;
2+ const core = require ( './core' ) ;
3+ const path = require ( 'path' ) ;
4+ const yaml = require ( 'js-yaml' ) ;
5+ const fs = require ( 'fs' ) ;
6+ const inject = require ( 'gulp-inject' ) ;
7+ const _ = require ( 'lodash' ) ;
8+ const browserSync = require ( 'browser-sync' ) ;
9+ const glob = require ( 'glob' ) ;
10+
11+ module . exports = ( gulp , config , tasks ) => {
12+ let plConfig = yaml . safeLoad (
13+ fs . readFileSync ( config . patternLab . configFile , 'utf8' )
14+ ) ;
15+ const plRoot = path . join ( config . patternLab . configFile , '../..' ) ;
16+ const plSource = path . join ( plRoot , plConfig . sourceDir ) ;
17+ const plPublic = path . join ( plRoot , plConfig . publicDir ) ;
18+ const plMeta = path . join ( plSource , '/_meta' ) ;
19+ const consolePath = path . join ( plRoot , 'core/console' ) ;
20+ const watchTriggeredTasks = [ ] ;
21+
22+ function plBuild ( done , errorShouldExit ) {
23+ core . sh ( `php ${ consolePath } --generate` , errorShouldExit , ( err ) => {
24+ if ( config . browserSync . enabled ) {
25+ browserSync . get ( 'server' ) . reload ( ) ;
26+ }
27+ done ( err ) ;
28+ } ) ;
29+ }
30+
31+ gulp . task ( 'pl' , done => plBuild ( done , true ) ) ;
32+
33+ // Begin `<link>` & `<script>` injecting code.
34+ // Will look for these HTML comments in `plSource/_meta/*.twig:
35+ // `<!-- inject:css -->`
36+ // `<!-- endinject -->`
37+ // `<!-- inject:js -->`
38+ // `<!-- endinject -->`
39+
40+ function injectPl ( done ) {
41+ let sources = [ ] ;
42+ if ( config . patternLab . injectFiles ) {
43+ sources = sources . concat ( config . patternLab . injectFiles ) ;
44+ }
45+ sources = sources . concat ( glob . sync ( path . normalize ( `${ config . js . dest } /*.js` ) ) ) ;
46+ sources = sources . concat ( glob . sync ( path . normalize ( `${ config . css . dest } /*.css` ) ) ) ;
47+ // We need to make sure our JS deps like jQuery are loaded before ours (`config.js.destName`)
48+ const rearrangedSources = [ ] ;
49+ sources . forEach ( ( source ) => {
50+ if ( path . basename ( source ) === config . js . destName ) {
51+ // add to end
52+ rearrangedSources . push ( source ) ;
53+ } else {
54+ // add to beginning
55+ rearrangedSources . unshift ( source ) ;
56+ }
57+ } ) ;
58+
59+ gulp
60+ . src ( [ '*.twig' ] , { cwd : plMeta } )
61+ . pipe ( inject ( gulp . src ( rearrangedSources , { read : false } ) , {
62+ relative : false ,
63+ addRootSlash : false ,
64+ addSuffix : '?cacheBuster={{ cacheBuster }}' ,
65+ addPrefix : path . join ( '../..' , path . relative ( plPublic , process . cwd ( ) ) ) ,
66+ } ) )
67+ . pipe ( gulp . dest ( plMeta ) )
68+ . on ( 'end' , done ) ;
69+ }
70+
71+ gulp . task ( 'inject:pl' , injectPl ) ;
72+
73+ const plFullDependencies = [ 'inject:pl' ] ;
74+
75+ // turns scss files full of variables into json files that PL can iterate on
76+ function scssToJson ( done ) {
77+ config . patternLab . scssToJson . forEach ( ( pair ) => {
78+ const scssVarList = _ . filter ( fs . readFileSync ( pair . src , 'utf8' ) . split ( '\n' ) , item => _ . startsWith ( item , pair . lineStartsWith ) ) ;
79+ let varsAndValues = _ . map ( scssVarList , ( item ) => {
80+ // assuming `item` is `$color-gray: hsl(0, 0%, 50%); // main gray color`
81+ const x = item . split ( ':' ) ;
82+ const y = x [ 1 ] . split ( ';' ) ;
83+ return {
84+ name : x [ 0 ] . trim ( ) , // i.e. $color-gray
85+ value : y [ 0 ] . replace ( / ! .* / , '' ) . trim ( ) , // i.e. hsl(0, 0%, 50%) after removing `!default`
86+ comment : y [ 1 ] . replace ( '//' , '' ) . trim ( ) , // any inline comment coming after, i.e. `// main gray color`
87+ } ;
88+ } ) ;
89+
90+ if ( ! pair . allowVarValues ) {
91+ varsAndValues = _ . filter ( varsAndValues , item => ! _ . startsWith ( item . value , '$' ) ) ;
92+ }
93+
94+ fs . writeFileSync ( pair . dest , JSON . stringify ( {
95+ items : varsAndValues ,
96+ meta : {
97+ description : `To add to these items, use Sass variables that start with <code>${ pair . lineStartsWith } </code> in <code>${ pair . src } </code>` ,
98+ } ,
99+ } , null , ' ' ) ) ;
100+ } ) ;
101+ done ( ) ;
102+ }
103+
104+ if ( config . patternLab . scssToJson ) {
105+ gulp . task ( 'pl:scss-to-json' , scssToJson ) ;
106+ plFullDependencies . push ( 'pl:scss-to-json' ) ;
107+
108+ gulp . task ( 'watch:pl:scss-to-json' , ( ) => {
109+ const files = config . patternLab . scssToJson . map ( file => file . src ) ;
110+ gulp . watch ( files , scssToJson ) ;
111+ } ) ;
112+ tasks . watch . push ( 'watch:pl:scss-to-json' ) ;
113+ }
114+
115+ function getTwigNamespaceConfig ( workingDir ) {
116+ workingDir = workingDir || process . cwd ( ) ; // eslint-disable-line no-param-reassign
117+ const twigNamespaceConfig = { } ;
118+ config . patternLab . twigNamespaces . sets . forEach ( ( namespaceSet ) => {
119+ const pathArray = namespaceSet . paths . map ( ( pathBase ) => {
120+ const results = glob . sync ( path . join ( pathBase , '**/*.twig' ) ) . map ( ( pathItem ) => { // eslint-disable-line arrow-body-style
121+ return path . relative ( workingDir , path . dirname ( pathItem ) ) ;
122+ } ) ;
123+ results . unshift ( path . relative ( workingDir , pathBase ) ) ;
124+ return results ;
125+ } ) ;
126+ twigNamespaceConfig [ namespaceSet . namespace ] = {
127+ paths : core . uniqueArray ( core . flattenArray ( pathArray ) ) ,
128+ } ;
129+ } ) ;
130+ return twigNamespaceConfig ;
131+ }
132+
133+ function addTwigNamespaceConfigToDrupal ( done ) {
134+ const twigNamespaceConfig = getTwigNamespaceConfig ( path . dirname ( config . drupal . themeFile ) ) ;
135+ const drupalThemeFile = yaml . safeLoad (
136+ fs . readFileSync ( config . drupal . themeFile , 'utf8' )
137+ ) ;
138+ Object . assign ( drupalThemeFile [ 'component-libraries' ] , twigNamespaceConfig ) ;
139+ const newThemeFile = yaml . safeDump ( drupalThemeFile ) ;
140+ fs . writeFileSync ( config . drupal . themeFile , newThemeFile , 'utf8' ) ;
141+ done ( ) ;
142+ }
143+
144+ function addTwigNamespaceConfigToPl ( done ) {
145+ const twigNamespaceConfig = getTwigNamespaceConfig ( plRoot ) ;
146+ plConfig = yaml . safeLoad (
147+ fs . readFileSync ( config . patternLab . configFile , 'utf8' )
148+ ) ;
149+ if ( ! plConfig . plugins ) {
150+ Object . assign ( plConfig , {
151+ plugins : {
152+ twigNamespaces : { enabled : true , namespaces : { } } ,
153+ } ,
154+ } ) ;
155+ } else if ( ! plConfig . plugins . twigNamespaces ) {
156+ Object . assign ( plConfig . plugins , {
157+ twigNamespaces : { enabled : true , namespaces : { } } ,
158+ } ) ;
159+ } else if ( ! plConfig . plugins . twigNamespaces . namespaces ) {
160+ plConfig . plugins . twigNamespaces . namespaces = { } ;
161+ }
162+ Object . assign ( plConfig . plugins . twigNamespaces . namespaces , twigNamespaceConfig ) ;
163+ const newConfigFile = yaml . safeDump ( plConfig ) ;
164+ fs . writeFileSync ( config . patternLab . configFile , newConfigFile , 'utf8' ) ;
165+ done ( ) ;
166+ }
167+
168+ if ( config . patternLab . twigNamespaces ) {
169+ gulp . task ( 'twigNamespaces' , ( done ) => {
170+ addTwigNamespaceConfigToPl ( ( ) => {
171+ if ( config . patternLab . twigNamespaces . addToDrupalThemeFile ) {
172+ addTwigNamespaceConfigToDrupal ( done ) ;
173+ }
174+ done ( ) ;
175+ } ) ;
176+ } ) ;
177+ plFullDependencies . push ( 'twigNamespaces' ) ;
178+ watchTriggeredTasks . push ( 'twigNamespaces' ) ;
179+ }
180+
181+ gulp . task ( 'pl:full' , gulp . series ( plFullDependencies , plBuild ) ) ;
182+
183+ const watchedExtensions = config . patternLab . watchedExtensions . join ( ',' ) ;
184+ gulp . task ( 'watch:pl' , ( ) => {
185+ const plGlob = [ path . normalize ( `${ plSource } /**/*.{${ watchedExtensions } }` ) ] ;
186+ const src = config . patternLab . extraWatches
187+ ? [ ] . concat ( plGlob , config . patternLab . extraWatches )
188+ : plGlob ;
189+ // plBuild goes last after any deps
190+ watchTriggeredTasks . push ( plBuild ) ;
191+ gulp . watch ( src , gulp . series ( watchTriggeredTasks ) ) ;
192+ } ) ;
193+
194+ tasks . watch . push ( 'watch:pl' ) ;
195+ tasks . compile . push ( 'pl:full' ) ;
196+ } ;
0 commit comments