Skip to content

Commit e4bbc1f

Browse files
committed
Implement cdsExtractorLog for consistent logging
Creates tests and code for a new, unified `cdsExtractorLog` function and integrates this function throughout the CDS extractor code. Updates `test/jest.setup.ts` config for the CDS extractor in order to simplify setup of the source root directory config required by the new `cdsExtractorLog` function.
1 parent aaab73b commit e4bbc1f

23 files changed

+625
-113
lines changed

extractors/cds/tools/cds-extractor.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { CdsProjectMapWithDebugSignals } from './src/cds/parser/types';
88
import { runJavaScriptExtractor } from './src/codeql';
99
import { addCompilationDiagnostic } from './src/diagnostics';
1010
import { configureLgtmIndexFilters, setupAndValidateEnvironment } from './src/environment';
11+
import { cdsExtractorLog, setSourceRootDirectory } from './src/logging';
1112
import { installDependencies } from './src/packageManager';
1213
import { RunMode } from './src/runMode';
1314
import { validateArguments } from './src/utils';
@@ -25,9 +26,12 @@ if (!validationResult.isValid) {
2526
// Get the validated and sanitized arguments
2627
const { runMode, sourceRoot } = validationResult.args!;
2728

29+
// Initialize the unified logging system with the source root directory
30+
setSourceRootDirectory(sourceRoot);
31+
2832
// Check for autobuild mode
2933
if (runMode === (RunMode.AUTOBUILD as string)) {
30-
console.log('Autobuild mode is not implemented yet.');
34+
cdsExtractorLog('info', 'Autobuild mode is not implemented yet.');
3135
process.exit(1);
3236
}
3337

@@ -43,7 +47,8 @@ const {
4347

4448
if (!envSetupSuccess) {
4549
const codeqlExe = platformInfo.isWindows ? 'codeql.exe' : 'codeql';
46-
console.warn(
50+
cdsExtractorLog(
51+
'warn',
4752
`'${codeqlExe} database index-files --language cds' terminated early due to: ${errorMessages.join(
4853
', ',
4954
)}.`,
@@ -56,12 +61,13 @@ if (!envSetupSuccess) {
5661
// directory as the current working directory.
5762
process.chdir(sourceRoot);
5863

59-
console.log(
60-
`INFO: CodeQL CDS extractor using run mode '${runMode}' for scan of project source root directory '${sourceRoot}'.`,
64+
cdsExtractorLog(
65+
'info',
66+
`CodeQL CDS extractor using run mode '${runMode}' for scan of project source root directory '${sourceRoot}'.`,
6167
);
6268

6369
// Using the new project-aware approach to find CDS projects and their dependencies
64-
console.log('Detecting CDS projects and analyzing their structure...');
70+
cdsExtractorLog('info', 'Detecting CDS projects and analyzing their structure...');
6571

6672
// Build the project dependency graph using the project-aware parser
6773
// Pass the script directory (__dirname) to support debug-parser mode internally
@@ -72,20 +78,23 @@ const typedProjectMap = projectMap as CdsProjectMapWithDebugSignals;
7278

7379
// Check if we're in debug-parser mode and should exit (based on signals from buildCdsProjectDependencyGraph)
7480
if (typedProjectMap.__debugParserSuccess) {
75-
console.log('Debug parser mode completed successfully.');
81+
cdsExtractorLog('info', 'Debug parser mode completed successfully.');
7682
process.exit(0);
7783
} else if (typedProjectMap.__debugParserFailure) {
78-
console.warn('No CDS projects found. Cannot generate debug information.');
84+
cdsExtractorLog('warn', 'No CDS projects found. Cannot generate debug information.');
7985
process.exit(1);
8086
}
8187

8288
// Install dependencies of discovered CAP/CDS projects
83-
console.log('Ensuring dependencies are installed in cache for required CDS compiler versions...');
89+
cdsExtractorLog(
90+
'info',
91+
'Ensuring dependencies are installed in cache for required CDS compiler versions...',
92+
);
8493
const projectCacheDirMap = installDependencies(projectMap, sourceRoot, codeqlExePath);
8594

8695
const cdsFilePathsToProcess: string[] = [];
8796

88-
console.log('Extracting CDS files from discovered projects...');
97+
cdsExtractorLog('info', 'Extracting CDS files from discovered projects...');
8998

9099
// Use the project map to collect all `.cds` files from each project.
91100
// We want to "extract" all `.cds` files from all projects so that we have a copy
@@ -94,7 +103,7 @@ for (const [, project] of projectMap.entries()) {
94103
cdsFilePathsToProcess.push(...project.cdsFiles);
95104
}
96105

97-
console.log('Processing CDS files to JSON ...');
106+
cdsExtractorLog('info', 'Processing CDS files to JSON ...');
98107

99108
// Collect files that need compilation, handling project-level compilation
100109
const cdsFilesToCompile: string[] = [];
@@ -115,7 +124,8 @@ for (const [projectDir, project] of projectMap.entries()) {
115124
}
116125
}
117126

118-
console.log(
127+
cdsExtractorLog(
128+
'info',
119129
`Found ${cdsFilePathsToProcess.length} total CDS files, ${cdsFilesToCompile.length} files to compile (${projectsForProjectLevelCompilation.size} project-level compilations)`,
120130
);
121131

@@ -141,14 +151,16 @@ for (const rawCdsFilePath of cdsFilesToCompile) {
141151
);
142152

143153
if (!compilationResult.success && compilationResult.message) {
144-
console.error(
145-
`ERROR: adding diagnostic for source file=${rawCdsFilePath} : ${compilationResult.message} ...`,
154+
cdsExtractorLog(
155+
'error',
156+
`adding diagnostic for source file=${rawCdsFilePath} : ${compilationResult.message} ...`,
146157
);
147158
addCompilationDiagnostic(rawCdsFilePath, compilationResult.message, codeqlExePath);
148159
}
149160
} catch (errorMessage) {
150-
console.error(
151-
`ERROR: adding diagnostic for source file=${rawCdsFilePath} : ${String(errorMessage)} ...`,
161+
cdsExtractorLog(
162+
'error',
163+
`adding diagnostic for source file=${rawCdsFilePath} : ${String(errorMessage)} ...`,
152164
);
153165
addCompilationDiagnostic(rawCdsFilePath, String(errorMessage), codeqlExePath);
154166
}
@@ -160,7 +172,7 @@ configureLgtmIndexFilters();
160172
// Run CodeQL's JavaScript extractor to process the compiled JSON files.
161173
const extractorResult = runJavaScriptExtractor(sourceRoot, autobuildScriptPath, codeqlExePath);
162174
if (!extractorResult.success && extractorResult.error) {
163-
console.error(`Error running JavaScript extractor: ${extractorResult.error}`);
175+
cdsExtractorLog('error', `Error running JavaScript extractor: ${extractorResult.error}`);
164176
}
165177

166178
// Use the `cds-extractor.js` name in the log message as that is the name of the script

extractors/cds/tools/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
"tmp": "^0.2.3"
2727
},
2828
"devDependencies": {
29-
"@eslint/compat": "^1.2.9",
29+
"@eslint/compat": "^1.3.0",
3030
"@eslint/eslintrc": "^3.3.1",
3131
"@eslint/js": "^9.28.0",
3232
"@types/glob": "^8.1.0",
3333
"@types/jest": "^29.5.14",
3434
"@types/mock-fs": "^4.13.4",
35-
"@types/node": "^24.0.0",
35+
"@types/node": "^24.0.1",
3636
"@types/shell-quote": "^1.7.5",
3737
"@typescript-eslint/eslint-plugin": "^8.34.0",
3838
"@typescript-eslint/parser": "^8.34.0",
@@ -43,7 +43,7 @@
4343
"eslint-plugin-jest": "^28.13.3",
4444
"eslint-plugin-prettier": "^5.4.1",
4545
"globals": "^16.2.0",
46-
"jest": "^30.0.0",
46+
"jest": "^29.7.0",
4747
"mock-fs": "^5.5.0",
4848
"prettier": "^3.5.3",
4949
"ts-jest": "^29.3.4",

extractors/cds/tools/src/cds/compiler/compile.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { resolve, join, delimiter, relative } from 'path';
44
import { CdsCompilationResult } from './types';
55
import { getCdsVersion } from './version';
66
import { fileExists, dirExists, recursivelyRenameJsonFiles } from '../../filesystem';
7+
import { cdsExtractorLog } from '../../logging';
78
import { CdsProject } from '../parser/types';
89

910
/**
@@ -59,7 +60,8 @@ function compileProjectLevel(
5960
spawnOptions: SpawnSyncOptions,
6061
versionInfo: string,
6162
): CdsCompilationResult {
62-
console.log(
63+
cdsExtractorLog(
64+
'info',
6365
`${resolvedCdsFilePath} is part of a CAP project - using project-aware compilation ${versionInfo}...`,
6466
);
6567

@@ -102,7 +104,7 @@ function compileProjectLevel(
102104
'warn',
103105
];
104106

105-
console.log(`Compiling CAP project directories: ${existingDirectories.join(', ')}`);
107+
cdsExtractorLog('info', `Compiling CAP project directories: ${existingDirectories.join(', ')}`);
106108

107109
// CRITICAL: Use the provided spawnOptions which has sourceRoot as cwd
108110
const result = spawnSync(cdsCommand, compileArgs, spawnOptions);
@@ -127,11 +129,14 @@ function compileProjectLevel(
127129

128130
// Handle directory output if the CDS compiler generated a directory
129131
if (dirExists(projectJsonOutPath)) {
130-
console.log(`CDS compiler generated JSON to output directory: ${projectJsonOutPath}`);
132+
cdsExtractorLog(
133+
'info',
134+
`CDS compiler generated JSON to output directory: ${projectJsonOutPath}`,
135+
);
131136
// Recursively rename all .json files to have a .cds.json extension
132137
recursivelyRenameJsonFiles(projectJsonOutPath);
133138
} else {
134-
console.log(`CDS compiler generated JSON to file: ${projectJsonOutPath}`);
139+
cdsExtractorLog('info', `CDS compiler generated JSON to file: ${projectJsonOutPath}`);
135140
}
136141

137142
return {
@@ -196,11 +201,11 @@ function compileIndividualFile(
196201

197202
// Handle directory output if the CDS compiler generated a directory
198203
if (dirExists(cdsJsonOutPath)) {
199-
console.log(`CDS compiler generated JSON to output directory: ${cdsJsonOutPath}`);
204+
cdsExtractorLog('info', `CDS compiler generated JSON to output directory: ${cdsJsonOutPath}`);
200205
// Recursively rename all .json files to have a .cds.json extension
201206
recursivelyRenameJsonFiles(cdsJsonOutPath);
202207
} else {
203-
console.log(`CDS compiler generated JSON to file: ${cdsJsonOutPath}`);
208+
cdsExtractorLog('info', `CDS compiler generated JSON to file: ${cdsJsonOutPath}`);
204209
}
205210

206211
return {
@@ -286,7 +291,8 @@ export function compileCdsToJson(
286291

287292
// Check if this file is in the list of files to compile for this project
288293
if (!shouldCompileIndividually(project, relativePath)) {
289-
console.log(
294+
cdsExtractorLog(
295+
'info',
290296
`${resolvedCdsFilePath} is imported by other files - will be compiled as part of a project ${versionInfo}...`,
291297
);
292298
return {
@@ -296,13 +302,17 @@ export function compileCdsToJson(
296302
message: 'File was compiled as part of a project-based compilation',
297303
};
298304
} else {
299-
console.log(
305+
cdsExtractorLog(
306+
'info',
300307
`${resolvedCdsFilePath} identified as a root CDS file - using individual file compilation ${versionInfo}...`,
301308
);
302309
}
303310
} else {
304311
// Fallback to individual file compilation if project information is not available
305-
console.log(`Processing individual CDS file ${resolvedCdsFilePath} ${versionInfo}...`);
312+
cdsExtractorLog(
313+
'info',
314+
`Processing individual CDS file ${resolvedCdsFilePath} ${versionInfo}...`,
315+
);
306316
}
307317

308318
return compileIndividualFile(resolvedCdsFilePath, cdsCommand, spawnOptions, !!isProjectAware);

extractors/cds/tools/src/cds/parser/debug.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { writeFileSync, mkdirSync, existsSync } from 'fs';
22
import { join } from 'path';
33

44
import { CdsProject } from './types';
5+
import { cdsExtractorLog } from '../../logging';
56

67
const PARSER_DEBUG_FILE = 'cds-extractor.parser.debug.txt';
78
const PARSER_DEBUG_SUBDIR = 'debug';
@@ -22,7 +23,10 @@ export function writeParserDebugInfo(
2223
try {
2324
// Early check if project map is empty
2425
if (!projectMap || projectMap.size === 0) {
25-
console.warn('Cannot write debug information: Empty project map or no CDS projects found.');
26+
cdsExtractorLog(
27+
'warn',
28+
'Cannot write debug information: Empty project map or no CDS projects found.',
29+
);
2630
return false;
2731
}
2832

@@ -112,10 +116,10 @@ export function writeParserDebugInfo(
112116
// cat/read when debugging.
113117
writeFileSync(debugFilePath, `${outputLines.join('\n')}\n`, 'utf-8');
114118

115-
console.log(`INFO: CDS extractor parser debug information written to: ${debugFilePath}`);
119+
cdsExtractorLog('info', `CDS extractor parser debug information written to: ${debugFilePath}`);
116120
return true;
117121
} catch (error: unknown) {
118-
console.error(`Error writing parser debug information: ${String(error)}`);
122+
cdsExtractorLog('error', `Error writing parser debug information: ${String(error)}`);
119123
return false;
120124
}
121125
}

extractors/cds/tools/src/cds/parser/functions.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
FileCache,
1616
PackageJson,
1717
} from './types';
18+
import { cdsExtractorLog } from '../../logging';
1819

1920
// Global file cache to avoid multiple reads of the same file
2021
const fileCache: FileCache = {
@@ -200,7 +201,7 @@ export function determineCdsFilesForProjectDir(
200201
// Convert absolute paths to paths relative to sourceRootDir
201202
return cdsFiles.map(file => relative(sourceRootDir, file));
202203
} catch (error: unknown) {
203-
console.error(`Error finding CDS files in ${projectDir}: ${String(error)}`);
204+
cdsExtractorLog('error', `Error finding CDS files in ${projectDir}: ${String(error)}`);
204205
return [];
205206
}
206207
}
@@ -664,7 +665,7 @@ export function isLikelyCdsProject(dir: string): boolean {
664665

665666
return false;
666667
} catch (error: unknown) {
667-
console.error(`Error checking directory ${dir}: ${String(error)}`);
668+
cdsExtractorLog('error', `Error checking directory ${dir}: ${String(error)}`);
668669
return false;
669670
}
670671
}
@@ -958,7 +959,7 @@ export function processCdsProject(sourceRootDir: string, projectDir: string): Cd
958959
const result = parseCdsFile(absoluteFilePath);
959960
parseResults.push(result);
960961
} catch (error: unknown) {
961-
console.error(`Error processing file ${absoluteFilePath}: ${String(error)}`);
962+
cdsExtractorLog('error', `Error processing file ${absoluteFilePath}: ${String(error)}`);
962963
// Add an empty result with the error
963964
parseResults.push({
964965
entities: [],
@@ -989,7 +990,7 @@ export function readFileWithCache(filePath: string): string {
989990
fileCache.fileContents.set(filePath, content);
990991
return content;
991992
} catch (error) {
992-
console.error(`Error reading file ${filePath}: ${String(error)}`);
993+
cdsExtractorLog('error', `Error reading file ${filePath}: ${String(error)}`);
993994
throw error;
994995
}
995996
}
@@ -1014,7 +1015,7 @@ export function readPackageJsonWithCache(filePath: string): PackageJson | undefi
10141015
fileCache.packageJsonCache.set(filePath, packageJson);
10151016
return packageJson;
10161017
} catch (error) {
1017-
console.warn(`Error parsing package.json at ${filePath}: ${String(error)}`);
1018+
cdsExtractorLog('warn', `Error parsing package.json at ${filePath}: ${String(error)}`);
10181019
return undefined;
10191020
}
10201021
}
@@ -1088,7 +1089,7 @@ export function determineCdsFilesToCompile(
10881089
}
10891090
}
10901091
} catch (error) {
1091-
console.warn(`Warning: Error processing imports for ${file}: ${String(error)}`);
1092+
cdsExtractorLog('warn', `Error processing imports for ${file}: ${String(error)}`);
10921093
}
10931094
}
10941095

@@ -1105,16 +1106,18 @@ export function determineCdsFilesToCompile(
11051106

11061107
// If no root files were identified, fall back to compiling all files
11071108
if (rootFiles.length === 0) {
1108-
console.warn(
1109-
`Warning: No root CDS files identified in project ${project.projectDir}, will compile all files`,
1109+
cdsExtractorLog(
1110+
'warn',
1111+
`No root CDS files identified in project ${project.projectDir}, will compile all files`,
11101112
);
11111113
return [...project.cdsFiles];
11121114
}
11131115

11141116
return rootFiles;
11151117
} catch (error) {
1116-
console.warn(
1117-
`Warning: Error determining files to compile for project ${project.projectDir}: ${String(error)}`,
1118+
cdsExtractorLog(
1119+
'warn',
1120+
`Error determining files to compile for project ${project.projectDir}: ${String(error)}`,
11181121
);
11191122
// Fall back to compiling all files on error
11201123
return [...project.cdsFiles];

0 commit comments

Comments
 (0)