@@ -4,50 +4,19 @@ import moxygen from "moxygen";
4
4
import assign from "object-assign" ;
5
5
import { program } from "commander" ;
6
6
import fs from "fs" ;
7
- import doxygen from "doxygen" ;
7
+ import DoxygenRunner from "./ doxygen-runner.js " ;
8
8
import { fileURLToPath } from 'url' ;
9
9
import { dirname } from 'path' ;
10
10
import path from "path" ;
11
+ import IssueResolver from "./issue-resolver.js" ;
12
+ import { createDirectories } from "./helpers.js" ;
11
13
12
14
const __filename = fileURLToPath ( import . meta. url ) ;
13
15
const __dirname = dirname ( __filename ) ;
14
16
15
17
const TEMPLATES_FOLDER = path . join ( __dirname , "templates/cpp" )
16
- const XML_FOLDER = "./build/xml/"
17
18
const PROGRAMMING_LANGUAGE = "cpp"
18
- const DOXYGEN_FILE_PATH = "./doxygen.config"
19
-
20
- /**
21
- * Creates directories if they do not exist.
22
- * @param {string[] } dirs - An array of directory paths.
23
- */
24
- const createDirectories = ( dirs ) => {
25
- for ( const dir of dirs ) {
26
- if ( ! fs . existsSync ( dir ) ) {
27
- fs . mkdirSync ( dir , { recursive : true } )
28
- }
29
- }
30
- }
31
-
32
- /**
33
- * Cleans the specified directory by removing all files and subdirectories recursively.
34
- * @param {string } dir - The directory path to be cleaned.
35
- */
36
- const cleanDirectory = ( dir ) => {
37
- if ( fs . existsSync ( dir ) ) {
38
- const files = fs . readdirSync ( dir )
39
- for ( const file of files ) {
40
- const path = dir + "/" + file
41
- const stat = fs . statSync ( path )
42
- if ( stat && stat . isDirectory ( ) ) {
43
- cleanDirectory ( path )
44
- fs . rmdirSync ( path )
45
- } else {
46
- fs . unlinkSync ( path )
47
- }
48
- }
49
- }
50
- }
19
+ const XML_FOLDER = "./build/xml/"
51
20
52
21
// Extract the command version from the package.json file
53
22
const version = JSON . parse ( fs . readFileSync ( path . join ( __dirname , 'package.json' ) ) ) . version ;
@@ -65,6 +34,7 @@ program.option('-c, --include-cpp', 'Process .cpp files when rendering the docum
65
34
program . option ( '-a, --access-level <string>' , 'Minimum access level to be considered (public, private)' , "public" )
66
35
program . option ( '-f, --fail-on-warnings' , 'Fail when undocumented code is found' , false )
67
36
program . option ( '-d, --debug' , 'Enable debugging mode with additional output.' , false )
37
+ program . option ( '-r, --resolve-issues' , 'Automatically fix issues in the documentation' , false )
68
38
69
39
if ( process . argv . length < 2 ) {
70
40
program . help ( ) ;
@@ -83,95 +53,37 @@ if (includeCppFiles) {
83
53
fileExtensions . push ( "*.cpp" )
84
54
}
85
55
86
- if ( outputXML ) {
87
- cleanDirectory ( "./build" )
88
- createDirectories ( [ "./build" ] )
89
- }
90
-
91
- // Check if output path exists. If not, create it.
92
- if ( outputFile ) {
93
- const outputFolder = path . dirname ( outputFile )
94
- createDirectories ( [ outputFolder ] )
95
- }
96
-
97
- if ( ! doxygen . isDoxygenExecutableInstalled ( ) ) {
98
- console . log ( `Doxygen is not installed. Downloading ...` )
99
- const success = await doxygen . downloadVersion ( ) ;
100
- if ( ! success ) {
101
- console . error ( "Failed to download Doxygen" )
102
- process . exit ( 1 )
56
+ try {
57
+ const options = {
58
+ "outputXML" : outputXML ,
59
+ "xmlFolder" : XML_FOLDER ,
60
+ "sourceFolder" : sourceFolder ,
61
+ "fileExtensions" : fileExtensions ,
62
+ "exclude" : commandOptions . exclude ,
63
+ "accessLevel" : commandOptions . accessLevel ,
64
+ "failOnWarnings" : commandOptions . failOnWarnings ,
65
+ "debug" : commandOptions . debug
103
66
}
104
- }
105
-
106
- // The configuration options for Doxygen
107
- const doxyFileOptions = {
108
- INPUT : sourceFolder ,
109
- RECURSIVE : "YES" ,
110
- GENERATE_HTML : "NO" ,
111
- GENERATE_LATEX : "NO" ,
112
- GENERATE_XML : outputXML ? "YES" : "NO" , // XML output is required for moxygen
113
- XML_OUTPUT : XML_FOLDER ,
114
- CASE_SENSE_NAMES : "NO" , // Creates case insensitive links compatible with GitHub
115
- INCLUDE_FILE_PATTERNS : fileExtensions . join ( " " ) ,
116
- EXCLUDE_PATTERNS : commandOptions . exclude ? commandOptions . exclude : "" ,
117
- EXTRACT_PRIVATE : commandOptions . accessLevel === "private" ? "YES" : "NO" ,
118
- EXTRACT_STATIC : "NO" ,
119
- QUIET : commandOptions . debug ? "NO" : "YES" ,
120
- WARN_NO_PARAMDOC : "YES" , // Warn if a parameter is not documented
121
- WARN_AS_ERROR : commandOptions . failOnWarnings ? "FAIL_ON_WARNINGS" : "NO" , // Treat warnings as errors. Continues if warnings are found.
122
- }
123
-
124
- if ( commandOptions . debug ) console . log ( `🔧 Creating Doxygen config file ${ DOXYGEN_FILE_PATH } ...` )
125
- doxygen . createConfig ( doxyFileOptions , DOXYGEN_FILE_PATH )
67
+ const doxygenRunner = new DoxygenRunner ( options )
68
+ await doxygenRunner . run ( )
126
69
127
- try {
128
- if ( commandOptions . debug ) console . log ( "🏃 Running Doxygen ..." )
129
- if ( doxyFileOptions . GENERATE_XML === "YES" ) {
130
- console . log ( `🔨 Generating XML documentation at ${ XML_FOLDER } ...` )
131
- }
132
- doxygen . run ( DOXYGEN_FILE_PATH )
133
70
} catch ( error ) {
134
- // Replace all "\n " with " " to meld the error messages into one line
135
- let errorMessages = error . stderr . toString ( ) . replace ( / \n / g, " " ) . split ( "\n" )
136
-
137
- // Filter out empty messages and allow only warnings related to documentation issues
138
- const filteredMessages = errorMessages . filter ( message => {
139
- const warningMessageRegex = / ^ (?: [ ^ : \n ] + ) : (?: \d + ) : w a r n i n g : (?: .+ ) $ /
140
- return message . match ( warningMessageRegex )
141
- } )
142
-
143
- if ( commandOptions . debug ) {
144
- // Print messages that were not filtered out and are not empty
145
- const remainingMessages = errorMessages . filter ( message => {
146
- return ! filteredMessages . includes ( message ) && message !== ""
147
- } )
148
- for ( const message of remainingMessages ) {
149
- console . warn ( `🤔 ${ message } ` )
150
- }
151
- }
71
+ const validationMessages = error . messages
152
72
153
- if ( filteredMessages . length > 0 && commandOptions . failOnWarnings ) {
73
+ if ( validationMessages && commandOptions . failOnWarnings ) {
154
74
console . error ( "❌ Issues in the documentation were found." )
155
- for ( const message of filteredMessages ) {
75
+ if ( commandOptions . resolveIssues ) {
76
+ console . log ( "🔨 Resolving issues ..." )
77
+ const resolver = new IssueResolver ( validationMessages , "<key>" )
78
+ await resolver . resolve ( )
79
+ }
80
+ for ( const message of validationMessages ) {
156
81
console . warn ( `😬 ${ message } ` )
157
82
}
158
83
process . exit ( 1 )
159
84
}
160
85
}
161
86
162
- if ( outputXML ) {
163
- const xmlFiles = fs . readdirSync ( XML_FOLDER )
164
- if ( xmlFiles . length === 0 ) {
165
- console . error ( `❌ No XML files found in ${ XML_FOLDER } .` )
166
- process . exit ( 1 )
167
- } else if ( commandOptions . debug ) {
168
- console . log ( `✅ Found ${ xmlFiles . length } XML files.` )
169
- for ( const file of xmlFiles ) {
170
- console . log ( `📄 ${ file } ` )
171
- }
172
- }
173
- }
174
-
175
87
// The configuration options for moxygen
176
88
const moxygenOptions = {
177
89
quiet : true , /** Do not output anything to the console **/
@@ -201,6 +113,13 @@ const finalMoxygenOptions = assign({}, moxygen.defaultOptions, {
201
113
} ) ;
202
114
203
115
if ( outputXML ) {
116
+ // Check if output path exists. If not, create it.
117
+ if ( outputFile ) {
118
+ const outputFolder = path . dirname ( outputFile )
119
+ if ( commandOptions . debug ) console . log ( `🔧 Creating output directory ${ outputFolder } ...` )
120
+ createDirectories ( [ outputFolder ] )
121
+ }
122
+
204
123
moxygen . logger . init ( finalMoxygenOptions ) ;
205
124
console . log ( "🔨 Generating markdown documentation..." )
206
125
moxygen . run ( finalMoxygenOptions ) ;
0 commit comments