@@ -3,17 +3,16 @@ import { join } from 'path';
33import { sync as globSync } from 'glob' ;
44
55import { orchestrateCompilation } from './src/cds/compiler' ;
6- import { buildCdsProjectDependencyGraph } from './src/cds/parser' ;
7- import { runJavaScriptExtractor } from './src/codeql' ;
6+ import { buildCdsProjectDependencyGraph , type CdsDependencyGraph } from './src/cds/parser' ;
7+ import { handleEarlyExit , runJavaScriptExtractionWithMarker } from './src/codeql' ;
88import {
99 addCompilationDiagnostic ,
1010 addDependencyGraphDiagnostic ,
1111 addDependencyInstallationDiagnostic ,
1212 addEnvironmentSetupDiagnostic ,
13- addJavaScriptExtractorDiagnostic ,
1413 addNoCdsProjectsDiagnostic ,
1514} from './src/diagnostics' ;
16- import { configureLgtmIndexFilters , setupAndValidateEnvironment } from './src/environment' ;
15+ import { setupAndValidateEnvironment } from './src/environment' ;
1716import {
1817 cdsExtractorLog ,
1918 generateStatusReport ,
@@ -27,31 +26,28 @@ import {
2726import { cacheInstallDependencies } from './src/packageManager' ;
2827import { validateArguments } from './src/utils' ;
2928
30- // Validate the script arguments.
29+ // ============================================================================
30+ // Main Extraction Flow
31+ // ============================================================================
32+
33+ // Validate arguments
3134const validationResult = validateArguments ( process . argv ) ;
3235if ( ! validationResult . isValid ) {
3336 console . warn ( validationResult . usageMessage ) ;
34- // For invalid arguments, we can't proceed but we also can't add diagnostics since we don't have
35- // the necessary context (sourceRoot, codeqlExePath). Log the issue and exit gracefully.
3637 console . log (
3738 `CDS extractor terminated due to invalid arguments: ${ validationResult . usageMessage } ` ,
3839 ) ;
3940 console . log ( `Completed run of the cds-extractor.js script for the CDS extractor.` ) ;
40- process . exit ( 0 ) ; // Use exit code 0 to not fail the overall JavaScript extractor
41+ process . exit ( 0 ) ;
4142}
4243
43- // Get the validated and sanitized arguments.
4444const { sourceRoot } = validationResult . args ! ;
4545
46- // Initialize the unified logging system with the source root directory.
46+ // Initialize logging
4747setSourceRootDirectory ( sourceRoot ) ;
48-
49- // Log the start of the CDS extractor session as a whole.
5048logExtractorStart ( sourceRoot ) ;
5149
52- // Setup the environment and validate all requirements first, before changing
53- // directory back to the "sourceRoot" directory. This ensures we can properly locate
54- // the CodeQL tools.
50+ // Setup and validate environment
5551logPerformanceTrackingStart ( 'Environment Setup' ) ;
5652const {
5753 success : envSetupSuccess ,
@@ -64,25 +60,18 @@ logPerformanceTrackingStop('Environment Setup');
6460
6561if ( ! envSetupSuccess ) {
6662 const codeqlExe = platformInfo . isWindows ? 'codeql.exe' : 'codeql' ;
67- const errorMessage = `'${ codeqlExe } database index-files --language cds' terminated early due to: ${ errorMessages . join (
68- ', ' ,
69- ) } .`;
70-
63+ const errorMessage = `'${ codeqlExe } database index-files --language cds' terminated early due to: ${ errorMessages . join ( ', ' ) } .` ;
7164 cdsExtractorLog ( 'warn' , errorMessage ) ;
7265
73- // Add diagnostic for environment setup failure if we have a codeqlExePath
7466 if ( codeqlExePath ) {
7567 addEnvironmentSetupDiagnostic ( sourceRoot , errorMessage , codeqlExePath ) ;
7668 }
7769
78- // Continue with a warning instead of exiting - let JavaScript extractor proceed
7970 logExtractorStop (
8071 false ,
8172 'Warning: Environment setup failed, continuing with limited functionality' ,
8273 ) ;
8374} else {
84- // Force this script, and any process it spawns, to use the project (source) root
85- // directory as the current working directory.
8675 process . chdir ( sourceRoot ) ;
8776}
8877
@@ -91,17 +80,9 @@ cdsExtractorLog(
9180 `CodeQL CDS extractor using autobuild mode for scan of project source root directory '${ sourceRoot } '.` ,
9281) ;
9382
83+ // Build CDS project dependency graph
9484cdsExtractorLog ( 'info' , 'Building CDS project dependency graph...' ) ;
95-
96- // Build the CDS project `dependencyGraph` as the foundation for the extraction process.
97- // This graph will contain all discovered CDS projects, their dependencies, the `.cds`
98- // files discovered within each project, the expected `.cds.json` files for each project
99- // and the compilation status of such `.cds.json` files.
100- //
101- // The `dependencyGraph` will be updated as CDS extractor phases progress, allowing for
102- // a single data structure to be used for planning, execution, retries (i.e. error handling),
103- // debugging, and final reporting.
104- let dependencyGraph ;
85+ let dependencyGraph : CdsDependencyGraph ;
10586
10687try {
10788 logPerformanceTrackingStart ( 'Dependency Graph Build' ) ;
11394 `${ dependencyGraph . projects . size } projects, ${ dependencyGraph . statusSummary . totalCdsFiles } CDS files` ,
11495 ) ;
11596
116- // Log details about discovered projects for debugging
97+ // Log project details
11798 if ( dependencyGraph . projects . size > 0 ) {
11899 for ( const [ projectDir , project ] of dependencyGraph . projects . entries ( ) ) {
119100 cdsExtractorLog (
@@ -122,11 +103,12 @@ try {
122103 ) ;
123104 }
124105 } else {
106+ // No CDS projects detected - try direct file search as diagnostic
125107 cdsExtractorLog (
126108 'error' ,
127109 'No CDS projects were detected. This is an unrecoverable error as there is nothing to scan.' ,
128110 ) ;
129- // Let's also try to find CDS files directly as a backup check
111+
130112 try {
131113 const allCdsFiles = Array . from (
132114 new Set ( [
@@ -139,6 +121,7 @@ try {
139121 'info' ,
140122 `Direct search found ${ allCdsFiles . length } CDS files in the source tree.` ,
141123 ) ;
124+
142125 if ( allCdsFiles . length > 0 ) {
143126 cdsExtractorLog (
144127 'info' ,
@@ -158,160 +141,96 @@ try {
158141 cdsExtractorLog ( 'warn' , `Could not perform direct CDS file search: ${ String ( globError ) } ` ) ;
159142 }
160143
161- // Add diagnostic warning for no CDS projects detected
162144 const warningMessage =
163145 'No CDS projects were detected. This may be expected if the source does not contain CAP/CDS projects.' ;
164146 if ( codeqlExePath ) {
165147 addNoCdsProjectsDiagnostic ( sourceRoot , warningMessage , codeqlExePath ) ;
166148 }
167149
168- // Continue instead of exiting - let JavaScript extractor proceed with non-CDS files
169150 logExtractorStop ( false , 'Warning: No CDS projects detected, skipping CDS-specific processing' ) ;
170-
171- // Skip the rest of CDS processing and go directly to JavaScript extraction
172- configureLgtmIndexFilters ( ) ;
173-
174- // Run CodeQL's JavaScript extractor to process any remaining files
175- logPerformanceTrackingStart ( 'JavaScript Extraction' ) ;
176- const extractorResult = runJavaScriptExtractor (
151+ handleEarlyExit (
177152 sourceRoot ,
178- autobuildScriptPath || '' , // Use empty string if autobuildScriptPath is undefined
153+ autobuildScriptPath || '' ,
179154 codeqlExePath ,
155+ 'JavaScript extraction completed (CDS processing was skipped)' ,
180156 ) ;
181- logPerformanceTrackingStop ( 'JavaScript Extraction' ) ;
182-
183- if ( ! extractorResult . success && extractorResult . error ) {
184- cdsExtractorLog ( 'error' , `Error running JavaScript extractor: ${ extractorResult . error } ` ) ;
185- if ( codeqlExePath ) {
186- addJavaScriptExtractorDiagnostic (
187- sourceRoot ,
188- extractorResult . error ,
189- codeqlExePath ,
190- sourceRoot ,
191- ) ;
192- }
193- logExtractorStop ( false , 'JavaScript extractor failed' ) ;
194- } else {
195- logExtractorStop ( true , 'JavaScript extraction completed (CDS processing was skipped)' ) ;
196- }
197-
198- console . log ( `Completed run of the cds-extractor.js script for the CDS extractor.` ) ;
199- process . exit ( 0 ) ; // Graceful exit to skip the rest of the processing
200157 }
201158} catch ( error ) {
202159 const errorMessage = `Failed to build CDS dependency graph: ${ String ( error ) } ` ;
203160 cdsExtractorLog ( 'error' , errorMessage ) ;
204161
205- // Add diagnostic for dependency graph build failure
206162 if ( codeqlExePath ) {
207163 addDependencyGraphDiagnostic ( sourceRoot , errorMessage , codeqlExePath ) ;
208164 }
209165
210- // Continue with a warning instead of exiting - let JavaScript extractor proceed with non-CDS files
211166 logExtractorStop (
212167 false ,
213168 'Warning: Dependency graph build failed, skipping CDS-specific processing' ,
214169 ) ;
215-
216- // Skip the rest of CDS processing and go directly to JavaScript extraction
217- configureLgtmIndexFilters ( ) ;
218-
219- // Run CodeQL's JavaScript extractor to process any remaining files
220- logPerformanceTrackingStart ( 'JavaScript Extraction' ) ;
221- const extractorResult = runJavaScriptExtractor (
170+ handleEarlyExit (
222171 sourceRoot ,
223- autobuildScriptPath || '' , // Use empty string if autobuildScriptPath is undefined
172+ autobuildScriptPath || '' ,
224173 codeqlExePath ,
174+ 'JavaScript extraction completed (CDS processing was skipped)' ,
225175 ) ;
226- logPerformanceTrackingStop ( 'JavaScript Extraction' ) ;
227-
228- if ( ! extractorResult . success && extractorResult . error ) {
229- cdsExtractorLog ( 'error' , `Error running JavaScript extractor: ${ extractorResult . error } ` ) ;
230- if ( codeqlExePath ) {
231- addJavaScriptExtractorDiagnostic (
232- sourceRoot ,
233- extractorResult . error ,
234- codeqlExePath ,
235- sourceRoot ,
236- ) ;
237- }
238- logExtractorStop ( false , 'JavaScript extractor failed' ) ;
239- } else {
240- logExtractorStop ( true , 'JavaScript extraction completed (CDS processing was skipped)' ) ;
241- }
242-
243- console . log ( `Completed run of the cds-extractor.js script for the CDS extractor.` ) ;
244- process . exit ( 0 ) ; // Graceful exit to skip the rest of the processing
245176}
246177
178+ // Install dependencies
247179logPerformanceTrackingStart ( 'Dependency Installation' ) ;
248180const projectCacheDirMap = cacheInstallDependencies ( dependencyGraph , sourceRoot , codeqlExePath ) ;
249181logPerformanceTrackingStop ( 'Dependency Installation' ) ;
250182
251- // Check if dependency installation resulted in any usable project mappings
252183if ( projectCacheDirMap . size === 0 ) {
253184 cdsExtractorLog (
254185 'error' ,
255186 'No project cache directory mappings were created. This indicates that dependency installation failed for all discovered projects.' ,
256187 ) ;
257188
258- // This is a critical error if we have projects but no cache mappings
259189 if ( dependencyGraph . projects . size > 0 ) {
260190 const errorMessage = `Found ${ dependencyGraph . projects . size } CDS projects but failed to install dependencies for any of them. Cannot proceed with compilation.` ;
261191 cdsExtractorLog ( 'error' , errorMessage ) ;
262192
263- // Add diagnostic for dependency installation failure
264193 if ( codeqlExePath ) {
265194 addDependencyInstallationDiagnostic ( sourceRoot , errorMessage , codeqlExePath ) ;
266195 }
267196
268- // Continue with a warning instead of exiting - let JavaScript extractor proceed
269197 logExtractorStop (
270198 false ,
271199 'Warning: Dependency installation failed for all projects, continuing with limited functionality' ,
272200 ) ;
273201 }
274202
275- // If we have no projects and no cache mappings, this should have been caught earlier
276203 cdsExtractorLog (
277204 'warn' ,
278205 'No projects and no cache mappings - this should have been detected earlier.' ,
279206 ) ;
280207}
281208
209+ // Collect all CDS files to process
282210const cdsFilePathsToProcess : string [ ] = [ ] ;
283-
284- // Use the dependency graph to collect all `.cds` files from each project.
285- // We want to "extract" all `.cds` files from all projects so that we have a copy
286- // of each `.cds` source file in the CodeQL database.
287211for ( const project of dependencyGraph . projects . values ( ) ) {
288212 cdsFilePathsToProcess . push ( ...project . cdsFiles ) ;
289213}
290214
291- // TODO : Improve logging / debugging of dependencyGraph.statusSummary. Just log the JSON?
292215cdsExtractorLog (
293216 'info' ,
294217 `Found ${ cdsFilePathsToProcess . length } total CDS files, ${ dependencyGraph . statusSummary . totalCdsFiles } CDS files in dependency graph` ,
295218) ;
296219
220+ // Compile CDS files
297221logPerformanceTrackingStart ( 'CDS Compilation' ) ;
298222try {
299- // Use the new orchestrated compilation approach (autobuild mode, no debug)
300223 orchestrateCompilation ( dependencyGraph , projectCacheDirMap , codeqlExePath ) ;
301224
302- // Handle compilation failures for normal mode
303225 if ( ! dependencyGraph . statusSummary . overallSuccess ) {
304226 cdsExtractorLog (
305227 'error' ,
306228 `Compilation completed with failures: ${ dependencyGraph . statusSummary . failedCompilations } failed out of ${ dependencyGraph . statusSummary . totalCompilationTasks } total tasks` ,
307229 ) ;
308230
309- // Add diagnostics for critical errors
310231 for ( const error of dependencyGraph . errors . critical ) {
311232 cdsExtractorLog ( 'error' , `Critical error in ${ error . phase } : ${ error . message } ` ) ;
312233 }
313-
314- // Don't exit with error - let the JavaScript extractor run on whatever was compiled
315234 }
316235
317236 logPerformanceTrackingStop ( 'CDS Compilation' ) ;
@@ -320,67 +239,32 @@ try {
320239 logPerformanceTrackingStop ( 'CDS Compilation' ) ;
321240 cdsExtractorLog ( 'error' , `Compilation orchestration failed: ${ String ( error ) } ` ) ;
322241
323- // Add diagnostic for the overall failure
324242 if ( cdsFilePathsToProcess . length > 0 ) {
325243 addCompilationDiagnostic (
326- cdsFilePathsToProcess [ 0 ] , // Use first file as representative
244+ cdsFilePathsToProcess [ 0 ] ,
327245 `Compilation orchestration failed: ${ String ( error ) } ` ,
328246 codeqlExePath ,
329247 sourceRoot ,
330248 ) ;
331249 }
332250}
333251
334- // Configure the "LGTM" index filters for proper extraction.
335- configureLgtmIndexFilters ( ) ;
336-
337- // Run CodeQL's JavaScript extractor to process the .cds source files and
338- // the compiled .cds.json files.
339- logPerformanceTrackingStart ( 'JavaScript Extraction' ) ;
340- const extractionStartTime = Date . now ( ) ;
341- const extractorResult = runJavaScriptExtractor ( sourceRoot , autobuildScriptPath , codeqlExePath ) ;
342- const extractionEndTime = Date . now ( ) ;
343- logPerformanceTrackingStop ( 'JavaScript Extraction' ) ;
344-
345- // Update the dependency graph's performance metrics with the extraction duration
346- dependencyGraph . statusSummary . performance . extractionDurationMs =
347- extractionEndTime - extractionStartTime ;
348-
349- // Calculate total duration by summing all phases
350- const totalDuration =
351- dependencyGraph . statusSummary . performance . parsingDurationMs +
352- dependencyGraph . statusSummary . performance . compilationDurationMs +
353- dependencyGraph . statusSummary . performance . extractionDurationMs ;
354- dependencyGraph . statusSummary . performance . totalDurationMs = totalDuration ;
355-
356- if ( ! extractorResult . success && extractorResult . error ) {
357- cdsExtractorLog ( 'error' , `Error running JavaScript extractor: ${ extractorResult . error } ` ) ;
358-
359- // Add diagnostic for JavaScript extractor failure
360- if ( codeqlExePath && dependencyGraph . projects . size > 0 ) {
361- // Use the first CDS file as a representative file for the diagnostic
362- const firstProject = Array . from ( dependencyGraph . projects . values ( ) ) [ 0 ] ;
363- const representativeFile = firstProject . cdsFiles [ 0 ] || sourceRoot ;
364- addJavaScriptExtractorDiagnostic (
365- representativeFile ,
366- extractorResult . error ,
367- codeqlExePath ,
368- sourceRoot ,
369- ) ;
370- }
252+ // Run JavaScript extraction with marker file handling
253+ const extractionSuccess = runJavaScriptExtractionWithMarker (
254+ sourceRoot ,
255+ autobuildScriptPath ,
256+ codeqlExePath ,
257+ dependencyGraph ,
258+ ) ;
371259
372- logExtractorStop ( false , 'JavaScript extractor failed' ) ;
373- } else {
374- logExtractorStop ( true , 'CDS extraction completed successfully' ) ;
375- }
260+ logExtractorStop (
261+ extractionSuccess ,
262+ extractionSuccess ? 'CDS extraction completed successfully' : 'JavaScript extractor failed' ,
263+ ) ;
376264
377265cdsExtractorLog (
378266 'info' ,
379267 'CDS Extractor Status Report : Final...\n' + generateStatusReport ( dependencyGraph ) ,
380268) ;
381269
382- // Use the `cds-extractor.js` name in the log message as that is the name of the script
383- // that is actually run by the `codeql database index-files` command. This TypeScript
384- // file is where the code/logic is edited/implemented, but the runnable script is
385- // generated by the TypeScript compiler and is named `cds-extractor.js`.
386270console . log ( `Completed run of the cds-extractor.js script for the CDS extractor.` ) ;
0 commit comments