@@ -68,11 +68,11 @@ const requireConfig = (dir, name, otherwise) => {
6868 ) ;
6969} ;
7070
71- // Main function
72- const main = async ( argv , logMessage , logError ) => {
73- // Output help for missing arguments
71+ // Process command-line arguments and return glob patterns
72+ const processArgv = ( argv , logMessage ) => {
7473 const globPatterns = argv . map ( ( glob ) => glob . replace ( / ^ # / u, "!" ) ) ;
7574 if ( globPatterns . length === 0 ) {
75+ // Output help if missing arguments
7676 const { name, version, author, homepage } = require ( "./package.json" ) ;
7777 /* eslint-disable max-len */
7878 logMessage ( `${ name } version ${ version } by ${ author . name } (${ author . url } )
@@ -111,118 +111,139 @@ Therefore, the most compatible glob syntax for cross-platform support:
111111$ ${ name } "**/*.md" "#node_modules"`
112112 ) ;
113113 /* eslint-enable max-len */
114- return 1 ;
114+ return null ;
115115 } else if ( ( globPatterns . length === 1 ) && ( globPatterns [ 0 ] === "." ) ) {
116116 // Substitute a more reasonable pattern
117117 globPatterns [ 0 ] = dotOnlySubstitute ;
118118 }
119+ return globPatterns ;
120+ } ;
119121
120- // Read base ignore globs to pass as globby patterns (best performance)
121- const tasks = [ ] ;
122- const dirToDirInfo = { } ;
123- const getAndProcessDirInfo = ( dir , func ) => {
124- let dirInfo = dirToDirInfo [ dir ] ;
125- if ( ! dirInfo ) {
126- dirInfo = {
127- dir,
128- "parent" : null ,
129- "files" : [ ] ,
130- "markdownlintConfig" : null ,
131- "markdownlintOptions" : null
132- } ;
133- dirToDirInfo [ dir ] = dirInfo ;
134- const markdownlintCli2Jsonc = path . join ( dir , ".markdownlint-cli2.jsonc" ) ;
135- const markdownlintCli2Yaml = path . join ( dir , ".markdownlint-cli2.yaml" ) ;
136- tasks . push (
137- fs . access ( markdownlintCli2Jsonc ) .
138- then (
139- ( ) => fs . readFile ( markdownlintCli2Jsonc , utf8 ) . then ( jsoncParse ) ,
140- ( ) => fs . access ( markdownlintCli2Yaml ) .
141- then (
142- ( ) => fs . readFile ( markdownlintCli2Yaml , utf8 ) . then ( yamlParse ) ,
143- requireConfig (
144- dir ,
145- ".markdownlint-cli2.js" ,
146- ( ) => null
147- )
122+ // Get (creating if necessary) and process a directory's info object
123+ const getAndProcessDirInfo = ( tasks , dirToDirInfo , dir , func ) => {
124+ let dirInfo = dirToDirInfo [ dir ] ;
125+ if ( ! dirInfo ) {
126+ dirInfo = {
127+ dir,
128+ "parent" : null ,
129+ "files" : [ ] ,
130+ "markdownlintConfig" : null ,
131+ "markdownlintOptions" : null
132+ } ;
133+ dirToDirInfo [ dir ] = dirInfo ;
134+
135+ // Load markdownlint-cli2 object(s)
136+ const markdownlintCli2Jsonc = path . join ( dir , ".markdownlint-cli2.jsonc" ) ;
137+ const markdownlintCli2Yaml = path . join ( dir , ".markdownlint-cli2.yaml" ) ;
138+ tasks . push (
139+ fs . access ( markdownlintCli2Jsonc ) .
140+ then (
141+ ( ) => fs . readFile ( markdownlintCli2Jsonc , utf8 ) . then ( jsoncParse ) ,
142+ ( ) => fs . access ( markdownlintCli2Yaml ) .
143+ then (
144+ ( ) => fs . readFile ( markdownlintCli2Yaml , utf8 ) . then ( yamlParse ) ,
145+ requireConfig (
146+ dir ,
147+ ".markdownlint-cli2.js" ,
148+ ( ) => null
148149 )
149- ) .
150- then ( ( options ) => {
151- dirInfo . markdownlintOptions = options ;
152- } )
153- ) ;
154- const readConfigs =
150+ )
151+ ) .
152+ then ( ( options ) => {
153+ dirInfo . markdownlintOptions = options ;
154+ } )
155+ ) ;
156+
157+ // Load markdownlint object(s)
158+ const readConfigs =
159+ readConfig (
160+ dir ,
161+ ".markdownlint.jsonc" ,
155162 readConfig (
156163 dir ,
157- ".markdownlint.jsonc " ,
164+ ".markdownlint.json " ,
158165 readConfig (
159166 dir ,
160- ".markdownlint.json " ,
167+ ".markdownlint.yaml " ,
161168 readConfig (
162169 dir ,
163- ".markdownlint.yaml " ,
164- readConfig (
170+ ".markdownlint.yml " ,
171+ requireConfig (
165172 dir ,
166- ".markdownlint.yml" ,
167- requireConfig (
168- dir ,
169- ".markdownlint.js" ,
170- ( ) => null
171- )
173+ ".markdownlint.js" ,
174+ ( ) => null
172175 )
173176 )
174177 )
175- ) ;
176- tasks . push (
177- readConfigs ( ) .
178- then ( ( config ) => {
179- dirInfo . markdownlintConfig = config ;
180- } )
178+ )
181179 ) ;
182- }
183- if ( func ) {
184- func ( dirInfo ) ;
185- }
186- return dirInfo ;
187- } ;
188- getAndProcessDirInfo ( "." ) ;
180+ tasks . push (
181+ readConfigs ( ) .
182+ then ( ( config ) => {
183+ dirInfo . markdownlintConfig = config ;
184+ } )
185+ ) ;
186+ }
187+ if ( func ) {
188+ func ( dirInfo ) ;
189+ }
190+ return dirInfo ;
191+ } ;
192+
193+ // Get base markdownlint-cli2 options object
194+ const getBaseOptions = async ( globPatterns ) => {
195+ const tasks = [ ] ;
196+ const dirToDirInfo = { } ;
197+ getAndProcessDirInfo ( tasks , dirToDirInfo , "." ) ;
189198 await Promise . all ( tasks ) ;
190- tasks . length = 0 ;
191199 const baseMarkdownlintOptions = dirToDirInfo [ "." ] . markdownlintOptions || { } ;
200+
201+ // Pass base ignore globs as globby patterns (best performance)
192202 const ignorePatterns = ( baseMarkdownlintOptions . ignores || [ ] ) .
193203 map ( negateGlob ) ;
194204 appendToArray ( globPatterns , ignorePatterns ) ;
195205 delete baseMarkdownlintOptions . ignores ;
196- const showProgress = ! baseMarkdownlintOptions . noProgress ;
206+ return {
207+ baseMarkdownlintOptions,
208+ dirToDirInfo
209+ } ;
210+ } ;
197211
198- // Enumerate files from globs and build directory info list
199- if ( showProgress ) {
200- logMessage ( `Finding: ${ globPatterns . join ( " " ) } ` ) ;
201- }
212+ // Enumerate files from globs and build directory infos
213+ const enumerateFiles = async ( globPatterns , dirToDirInfo ) => {
214+ const tasks = [ ] ;
202215 for await ( const file of globby . stream ( globPatterns ) ) {
203216 // @ts -ignore
204217 const dir = path . dirname ( file ) ;
205- getAndProcessDirInfo ( dir , ( dirInfo ) => {
218+ getAndProcessDirInfo ( tasks , dirToDirInfo , dir , ( dirInfo ) => {
206219 dirInfo . files . push ( file ) ;
207220 } ) ;
208221 }
209222 await Promise . all ( tasks ) ;
210- tasks . length = 0 ;
223+ } ;
211224
212- // Fill out directory info list with parent directories
225+ // Enumerate (possibly missing) parent directories and update directory infos
226+ const enumerateParents = async ( dirToDirInfo ) => {
227+ const tasks = [ ] ;
213228 for ( let lastDirInfo of Object . values ( dirToDirInfo ) ) {
214229 let { dir } = lastDirInfo ;
215230 let lastDir = dir ;
216231 while ( ( dir = path . dirname ( dir ) ) && ( dir !== lastDir ) ) {
217232 lastDir = dir ;
218- // eslint-disable-next-line no-loop-func
219- lastDirInfo = getAndProcessDirInfo ( dir , ( dirInfo ) => {
220- lastDirInfo . parent = dirInfo ;
221- } ) ;
233+ lastDirInfo =
234+ // eslint-disable-next-line no-loop-func
235+ getAndProcessDirInfo ( tasks , dirToDirInfo , dir , ( dirInfo ) => {
236+ lastDirInfo . parent = dirInfo ;
237+ } ) ;
222238 }
223239 }
224240 await Promise . all ( tasks ) ;
225- tasks . length = 0 ;
241+ } ;
242+
243+ // Create directory info objects by enumerating file globs
244+ const createDirInfos = async ( globPatterns , dirToDirInfo ) => {
245+ await enumerateFiles ( globPatterns , dirToDirInfo ) ;
246+ await enumerateParents ( dirToDirInfo ) ;
226247
227248 // Merge file lists with identical configuration
228249 const dirs = Object . keys ( dirToDirInfo ) ;
@@ -289,12 +310,12 @@ $ ${name} "**/*.md" "#node_modules"`
289310 }
290311 dirInfo . markdownlintOptions = markdownlintOptions ;
291312 }
313+ return dirInfos ;
314+ } ;
292315
293- // Lint each list of files
294- if ( showProgress ) {
295- const fileCount = dirInfos . reduce ( ( p , c ) => p + c . files . length , 0 ) ;
296- logMessage ( `Linting: ${ fileCount } file(s)` ) ;
297- }
316+ // Lint files in groups by shared configuration
317+ const lintFiles = async ( dirInfos ) => {
318+ const tasks = [ ] ;
298319 for ( const dirInfo of dirInfos ) {
299320 const { dir, files, markdownlintConfig, markdownlintOptions } = dirInfo ;
300321 let filteredFiles = files ;
@@ -308,18 +329,15 @@ $ ${name} "**/*.md" "#node_modules"`
308329 }
309330 const options = {
310331 "files" : filteredFiles ,
311- "config" :
312- markdownlintConfig || markdownlintOptions . config ,
313- "customRules" :
314- requireIds ( dir , markdownlintOptions . customRules || [ ] ) ,
332+ "config" : markdownlintConfig || markdownlintOptions . config ,
333+ "customRules" : requireIds ( dir , markdownlintOptions . customRules || [ ] ) ,
315334 "frontMatter" : markdownlintOptions . frontMatter
316335 ? new RegExp ( markdownlintOptions . frontMatter , "u" )
317336 : undefined ,
318337 "handleRuleFailures" : true ,
319338 "markdownItPlugins" :
320339 requireIdsAndParams ( dir , markdownlintOptions . markdownItPlugins || [ ] ) ,
321- "noInlineConfig" :
322- Boolean ( markdownlintOptions . noInlineConfig ) ,
340+ "noInlineConfig" : Boolean ( markdownlintOptions . noInlineConfig ) ,
323341 "resultVersion" : 3
324342 } ;
325343 let task = markdownlintPromise ( options ) ;
@@ -346,9 +364,11 @@ $ ${name} "**/*.md" "#node_modules"`
346364 tasks . push ( task ) ;
347365 }
348366 const taskResults = await Promise . all ( tasks ) ;
349- tasks . length = 0 ;
367+ return taskResults ;
368+ } ;
350369
351- // Create summary of results
370+ // Create summary of results
371+ const createSummary = ( taskResults ) => {
352372 const summary = [ ] ;
353373 let counter = 0 ;
354374 for ( const results of taskResults ) {
@@ -377,30 +397,56 @@ $ ${name} "**/*.md" "#node_modules"`
377397 ( a . counter - b . counter )
378398 ) ) ;
379399 summary . forEach ( ( result ) => delete result . counter ) ;
400+ return summary ;
401+ } ;
402+
403+ // Output summary via formatters
404+ const outputSummary =
405+ async ( summary , outputFormatters , logMessage , logError ) => {
406+ const errorsPresent = ( summary . length > 0 ) ;
407+ if ( errorsPresent || outputFormatters ) {
408+ const formatterOptions = {
409+ "results" : summary ,
410+ logMessage,
411+ logError
412+ } ;
413+ const formattersAndParams = requireIdsAndParams (
414+ "." ,
415+ outputFormatters || [ [ "markdownlint-cli2-formatter-default" ] ]
416+ ) ;
417+ await Promise . all ( formattersAndParams . map ( ( formatterAndParams ) => {
418+ const [ formatter , ...formatterParams ] = formatterAndParams ;
419+ return formatter ( formatterOptions , ...formatterParams ) ;
420+ } ) ) ;
421+ }
422+ return errorsPresent ;
423+ } ;
380424
381- // Output summary via formatters
425+ // Main function
426+ const main = async ( argv , logMessage , logError ) => {
427+ const globPatterns = processArgv ( argv , logMessage ) ;
428+ if ( ! globPatterns ) {
429+ return 1 ;
430+ }
431+ const { baseMarkdownlintOptions, dirToDirInfo } =
432+ await getBaseOptions ( globPatterns ) ;
433+ const showProgress = ! baseMarkdownlintOptions . noProgress ;
434+ if ( showProgress ) {
435+ logMessage ( `Finding: ${ globPatterns . join ( " " ) } ` ) ;
436+ }
437+ const dirInfos = await createDirInfos ( globPatterns , dirToDirInfo ) ;
438+ if ( showProgress ) {
439+ const fileCount = dirInfos . reduce ( ( p , c ) => p + c . files . length , 0 ) ;
440+ logMessage ( `Linting: ${ fileCount } file(s)` ) ;
441+ }
442+ const lintResults = await lintFiles ( dirInfos ) ;
443+ const summary = createSummary ( lintResults ) ;
382444 if ( showProgress ) {
383445 logMessage ( `Summary: ${ summary . length } error(s)` ) ;
384446 }
385447 const { outputFormatters } = baseMarkdownlintOptions ;
386- const errorsPresent = ( summary . length > 0 ) ;
387- if ( errorsPresent || outputFormatters ) {
388- const formatterOptions = {
389- "results" : summary ,
390- logMessage,
391- logError
392- } ;
393- const formattersAndParams = requireIdsAndParams (
394- "." ,
395- outputFormatters || [ [ "markdownlint-cli2-formatter-default" ] ]
396- ) ;
397- await Promise . all ( formattersAndParams . map ( ( formatterAndParams ) => {
398- const [ formatter , ...formatterParams ] = formatterAndParams ;
399- return formatter ( formatterOptions , ...formatterParams ) ;
400- } ) ) ;
401- }
402-
403- // Done
448+ const errorsPresent =
449+ await outputSummary ( summary , outputFormatters , logMessage , logError ) ;
404450 return errorsPresent ? 1 : 0 ;
405451} ;
406452
0 commit comments