@@ -84,18 +84,43 @@ function isRequired(relativeFilePath) {
8484 return required ;
8585}
8686
87+ /**
88+ * Check for valid paths within CSS folder structure
89+ * @private
90+ * @function isValidCssFolderPath
91+ * @param {String } relativeFilePath relative file/folder name
92+ * @param {String } topLevelFolder parent folder name
93+ * @param {Object } cssDirectoryStructure CSS directory structure
94+ * @return {Boolean }
95+ */
96+ function isValidCssFolderPath ( relativeFilePath , topLevelFolder , cssDirectoryStructure ) {
97+ for ( const folder of cssDirectoryStructure [ topLevelFolder ] ) {
98+ const validCssPath = path . join ( topLevelFolder , folder ) ;
99+
100+ if ( relativeFilePath . startsWith ( validCssPath ) ) {
101+ return true ;
102+ }
103+ }
104+
105+ return false ;
106+ }
107+
87108/**
88109 * Check if glob item is a valid folder name
89110 * If configFolders not set in config, all folders valid
90111 * @private
91112 * @function isFolder
92113 * @param {String } filePath full path to item
93114 * @param {String } relativeFilePath relative file/folder name
115+ * @param {Object } cssDirectoryStructure CSS directory structure
94116 * @param {String } brand optional name of the context brand
95117 * @return {Boolean }
96118 */
97- function isFolder ( filePath , relativeFilePath , brand ) {
119+ function isFolder ( filePath , relativeFilePath , cssDirectoryStructure , brand ) {
98120 const relativeFileName = ( brand ) ? `${ brand } /${ relativeFilePath } ` : relativeFilePath ;
121+ const splitGlob = relativeFilePath . split ( path . sep ) ;
122+ const topLevelFolder = splitGlob [ 0 ] ;
123+ let isValid = false ;
99124
100125 // This is not a directory
101126 if ( ! fs . lstatSync ( filePath ) . isDirectory ( ) ) {
@@ -107,8 +132,14 @@ function isFolder(filePath, relativeFilePath, brand) {
107132 return true ;
108133 }
109134
110- const splitGlob = relativeFilePath . split ( path . sep ) ;
111- const isValid = configFolders . includes ( splitGlob [ 0 ] ) ;
135+ // Valid CSS subfolder or valid topLevelFolder
136+ isValid = (
137+ cssDirectoryStructure && // CSS folder structure is set
138+ topLevelFolder in cssDirectoryStructure && // This is a CSS folder
139+ splitGlob . length > 1 // This is not the topLevelFolder CSS folder
140+ ) ?
141+ isValidCssFolderPath ( relativeFilePath , topLevelFolder , cssDirectoryStructure ) :
142+ configFolders . includes ( topLevelFolder ) ;
112143
113144 if ( isValid ) {
114145 reporter . success ( 'validating' , relativeFileName , 'is a valid folder' ) ;
@@ -126,12 +157,16 @@ function isFolder(filePath, relativeFilePath, brand) {
126157 * @private
127158 * @function isFileType
128159 * @param {String } relativeFilePath relative file/folder name
160+ * @param {Object } cssDirectoryStructure CSS directory structure
129161 * @param {String } brand optional name of the context brand
130162 * @return {Boolean }
131163 */
132- function isFileType ( relativeFilePath , brand ) {
164+ function isFileType ( relativeFilePath , cssDirectoryStructure , brand ) {
133165 const relativeFileName = ( brand ) ? `${ brand } /${ relativeFilePath } ` : relativeFilePath ;
134166 const splitGlob = relativeFilePath . split ( path . sep ) ;
167+ const topLevelFolder = splitGlob [ 0 ] ;
168+ const fileType = path . extname ( relativeFilePath ) . slice ( 1 ) ;
169+ let isValid = false ;
135170
136171 // This is a top level file
137172 if ( splitGlob . length === 1 ) {
@@ -143,12 +178,18 @@ function isFileType(relativeFilePath, brand) {
143178 return true ;
144179 }
145180
146- const topLevelFolder = splitGlob [ 0 ] ;
147- const fileType = path . extname ( relativeFilePath ) . slice ( 1 ) ;
148-
149181 // Is a valid extension within a valid folder?
150182 if ( configFolders . includes ( topLevelFolder ) ) {
151- const isValid = config . folders [ topLevelFolder ] . includes ( fileType ) ;
183+ const isValidFileType = configFolders . includes ( topLevelFolder ) && config . folders [ topLevelFolder ] . includes ( fileType ) ;
184+
185+ // Valid file in CSS subfolder or valid filetype within topLevelFolder
186+ isValid = (
187+ cssDirectoryStructure && // CSS folder structure is set
188+ topLevelFolder in cssDirectoryStructure && // This is a CSS folder
189+ splitGlob . length > 2 // not a file within top level CSS folder
190+ ) ?
191+ isValidCssFolderPath ( relativeFilePath , topLevelFolder , cssDirectoryStructure ) && isValidFileType :
192+ isValidFileType ;
152193
153194 if ( ! isValid ) {
154195 reporter . fail ( 'validating' , relativeFileName , 'is not a valid file' ) ;
@@ -207,10 +248,11 @@ function removeNonValidatedPaths(filePaths) {
207248 * @function checkPackageStructure
208249 * @param {String } pathToPackage package path on filesystem
209250 * @param {Object } globSettings configuration for glob search
251+ * @param {Object } cssDirectoryStructure CSS directory structure
210252 * @param {String } brand optional name of the context brand
211253 * @return {Promise }
212254 */
213- async function checkPackageStructure ( pathToPackage , globSettings , brand ) {
255+ async function checkPackageStructure ( pathToPackage , globSettings , cssDirectoryStructure , brand ) {
214256 try {
215257 const filePaths = await globby ( globSettings . pattern , globSettings . options ) ;
216258 const pathsToValidate = removeNonValidatedPaths ( filePaths ) ;
@@ -224,8 +266,8 @@ async function checkPackageStructure(pathToPackage, globSettings, brand) {
224266 if (
225267 ! isRequired ( relativeFilePath ) &&
226268 ! isBrandReadme ( brand , relativeFileName ) &&
227- ! isFolder ( filePath , relativeFilePath , brand ) &&
228- ! isFileType ( relativeFilePath , brand )
269+ ! isFolder ( filePath , relativeFilePath , cssDirectoryStructure , brand ) &&
270+ ! isFileType ( relativeFilePath , cssDirectoryStructure , brand )
229271 ) {
230272 // If not recongnised at any other step then invalid top level file
231273 reporter . fail ( 'validating' , relativeFileName , 'is not a valid top level file' ) ;
@@ -271,7 +313,8 @@ async function init(validationConfig, pathToPackage, configuredBrands) {
271313 {
272314 pattern : `${ pathToPackage } /*` ,
273315 options : { onlyFiles : true }
274- }
316+ } ,
317+ config . CSSDirectoryStructure
275318 ) ;
276319
277320 // Validate files within each brand
@@ -282,6 +325,7 @@ async function init(validationConfig, pathToPackage, configuredBrands) {
282325 pattern : `${ pathToPackage } /${ brand } /**/*` ,
283326 options : { onlyFiles : false }
284327 } ,
328+ config . CSSDirectoryStructure ,
285329 brand
286330 ) ;
287331 }
@@ -292,7 +336,8 @@ async function init(validationConfig, pathToPackage, configuredBrands) {
292336 {
293337 pattern : `${ pathToPackage } /**/*` ,
294338 options : { onlyFiles : false }
295- }
339+ } ,
340+ config . CSSDirectoryStructure
296341 ) ;
297342 }
298343
0 commit comments