Skip to content

Commit bade93d

Browse files
committed
fix(codeql): implement package.json handling to avoid ESM/CJS conflicts
* Added utility functions `temporarilyRenamePackageJsonIfTypeModule` and `restorePackageJson` to manage package.json renaming based on its type. * Updated `createDatabase` method to utilize these utilities for handling package.json in both filtered and root paths. * Introduced tests for the new utility functions to ensure correct behavior and logging.
1 parent 4c46d6e commit bade93d

5 files changed

Lines changed: 290 additions & 149 deletions

File tree

dist/index.js

Lines changed: 66 additions & 70 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/codeql/database.ts

Lines changed: 26 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import type { CodeQLConfig } from '../types';
2-
import * as fs from 'node:fs';
32
import * as process from 'node:process';
43
import { exec } from '@actions/exec';
54
import { FileUtils } from '../utils/file-utils';
65
import { Logger } from '../utils/logger';
6+
import {
7+
restorePackageJson,
8+
temporarilyRenamePackageJsonIfTypeModule,
9+
} from './utils/package-json-utils';
710

811
export class CodeQLDatabase {
912
static async createDatabase(
@@ -25,7 +28,6 @@ export class CodeQLDatabase {
2528
Logger.info(`Languages to analyze: ${languages.join(', ')}`);
2629
Logger.info(`Multi-language analysis: ${isMultiLanguage}`);
2730

28-
// --- START: ADDED CODE FOR THE FIX ---
2931
const packageJsonPath = FileUtils.joinPath(filteredPath, 'package.json');
3032
const packageJsonBackupPath = FileUtils.joinPath(filteredPath, 'package.json.bak');
3133
const rootPackageJsonPath = FileUtils.joinPath(process.cwd(), 'package.json');
@@ -35,79 +37,20 @@ export class CodeQLDatabase {
3537
);
3638
let needsCleanup = false;
3739
let needsRootCleanup = false;
38-
// --- END: ADDED CODE FOR THE FIX ---
3940

4041
try {
41-
// --- START: ADDED CODE FOR THE FIX ---
42-
// Check if package.json exists and contains "type": "module"
43-
Logger.info(`Looking for package.json in filtered path: ${packageJsonPath}`);
42+
// Use helpers to reduce duplication
43+
needsCleanup = temporarilyRenamePackageJsonIfTypeModule(
44+
packageJsonPath,
45+
packageJsonBackupPath,
46+
'filtered path',
47+
);
4448

45-
if (FileUtils.exists(packageJsonPath)) {
46-
Logger.info('package.json found. Reading file content.');
47-
const packageJsonContent = FileUtils.readFile(packageJsonPath);
48-
try {
49-
const parsed = JSON.parse(packageJsonContent) as unknown;
50-
if (typeof parsed === 'object' && parsed !== null && 'type' in parsed) {
51-
const packageJson = parsed as { type?: unknown };
52-
Logger.info(`Detected package.json.type = ${String(packageJson.type)}`);
53-
if (packageJson.type === 'module') {
54-
Logger.info(
55-
'Temporarily renaming package.json to avoid ESM/CJS conflict with CodeQL extractor.',
56-
);
57-
fs.renameSync(packageJsonPath, packageJsonBackupPath);
58-
needsCleanup = true;
59-
Logger.info('package.json was renamed to package.json.bak');
60-
} else {
61-
Logger.info('package.json.type is not "module". No rename necessary.');
62-
}
63-
} else {
64-
Logger.info(
65-
'package.json does not contain a "type" field. No rename necessary.',
66-
);
67-
}
68-
} catch (e) {
69-
Logger.warning(
70-
`Could not parse package.json. Skipping temporary rename. Error: ${e instanceof Error ? e.message : String(e)}`,
71-
);
72-
}
73-
} else {
74-
Logger.info('No package.json found in filtered path.');
75-
}
76-
77-
// Also check for package.json in the root directory (where CodeQL might also look)
78-
Logger.info(`Looking for package.json in root path: ${rootPackageJsonPath}`);
79-
if (FileUtils.exists(rootPackageJsonPath)) {
80-
Logger.info('Root package.json found. Reading file content.');
81-
const rootPackageJsonContent = FileUtils.readFile(rootPackageJsonPath);
82-
try {
83-
const parsed = JSON.parse(rootPackageJsonContent) as unknown;
84-
if (typeof parsed === 'object' && parsed !== null && 'type' in parsed) {
85-
const packageJson = parsed as { type?: unknown };
86-
Logger.info(`Detected root package.json.type = ${String(packageJson.type)}`);
87-
if (packageJson.type === 'module') {
88-
Logger.info(
89-
'Temporarily renaming root package.json to avoid ESM/CJS conflict with CodeQL extractor.',
90-
);
91-
fs.renameSync(rootPackageJsonPath, rootPackageJsonBackupPath);
92-
needsRootCleanup = true;
93-
Logger.info('Root package.json was renamed to package.json.bak');
94-
} else {
95-
Logger.info('Root package.json.type is not "module". No rename necessary.');
96-
}
97-
} else {
98-
Logger.info(
99-
'Root package.json does not contain a "type" field. No rename necessary.',
100-
);
101-
}
102-
} catch (e) {
103-
Logger.warning(
104-
`Could not parse root package.json. Skipping temporary rename. Error: ${e instanceof Error ? e.message : String(e)}`,
105-
);
106-
}
107-
} else {
108-
Logger.info('No package.json found in root path.');
109-
}
110-
// --- END: ADDED CODE FOR THE FIX ---
49+
needsRootCleanup = temporarilyRenamePackageJsonIfTypeModule(
50+
rootPackageJsonPath,
51+
rootPackageJsonBackupPath,
52+
'root path',
53+
);
11154

11255
const args = ['database', 'create', dbPath];
11356

@@ -121,19 +64,23 @@ export class CodeQLDatabase {
12164
}
12265

12366
args.push(`--source-root=${filteredPath}`);
124-
await exec(codeqlPath, args);
67+
try {
68+
await exec(codeqlPath, args);
69+
} catch (e) {
70+
// Log the error clearly, then rethrow so the finally block can restore package.json files
71+
Logger.error(
72+
`CodeQL execution failed: ${e instanceof Error ? e.message : String(e)}`,
73+
);
74+
throw e;
75+
}
12576
} finally {
126-
// --- START: ADDED CODE FOR THE FIX ---
12777
// Ensure package.json is restored even if exec fails
12878
if (needsCleanup) {
129-
Logger.info('Restoring original package.json.');
130-
fs.renameSync(packageJsonBackupPath, packageJsonPath);
79+
restorePackageJson(packageJsonBackupPath, packageJsonPath, 'filtered path');
13180
}
13281
if (needsRootCleanup) {
133-
Logger.info('Restoring original root package.json.');
134-
fs.renameSync(rootPackageJsonBackupPath, rootPackageJsonPath);
82+
restorePackageJson(rootPackageJsonBackupPath, rootPackageJsonPath, 'root path');
13583
}
136-
// --- END: ADDED CODE FOR THE FIX ---
13784
}
13885
}
13986

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import * as fs from 'node:fs';
2+
import { FileUtils } from '../../utils/file-utils';
3+
import { Logger } from '../../utils/logger';
4+
5+
/**
6+
* If a package.json exists at the given path and contains "type": "module",
7+
* rename it to the provided backup path to avoid ESM/CJS conflicts.
8+
* Returns true if a rename was performed, false otherwise.
9+
*/
10+
export function temporarilyRenamePackageJsonIfTypeModule(
11+
packageJsonPath: string,
12+
backupPath: string,
13+
description = 'path',
14+
): boolean {
15+
Logger.info(`Looking for package.json in ${description}: ${packageJsonPath}`);
16+
17+
if (!FileUtils.exists(packageJsonPath)) {
18+
Logger.info(`No package.json found in ${description}.`);
19+
return false;
20+
}
21+
22+
Logger.info('package.json found. Reading file content.');
23+
const packageJsonContent = FileUtils.readFile(packageJsonPath);
24+
try {
25+
const parsed = JSON.parse(packageJsonContent) as unknown;
26+
if (typeof parsed === 'object' && parsed !== null && 'type' in parsed) {
27+
const packageJson = parsed as { type?: unknown };
28+
Logger.info(`Detected package.json.type = ${String(packageJson.type)}`);
29+
if (packageJson.type === 'module') {
30+
Logger.info(
31+
`⚠️ Temporarily changing package.json type in ${description} to avoid ESM/CJS conflict with CodeQL extractor (typescript-parser-wrapper).`,
32+
);
33+
fs.renameSync(packageJsonPath, backupPath);
34+
Logger.info('package.json was renamed to package.json.bak');
35+
return true;
36+
}
37+
return false;
38+
}
39+
40+
return false;
41+
} catch (e) {
42+
Logger.warning(
43+
`Could not parse package.json in ${description}. Skipping temporary rename. Error: ${
44+
e instanceof Error ? e.message : String(e)
45+
}`,
46+
);
47+
return false;
48+
}
49+
}
50+
51+
/**
52+
* Restore a previously renamed package.json by moving backupPath back to packageJsonPath.
53+
* Logs a warning if the backup does not exist.
54+
*/
55+
export function restorePackageJson(
56+
backupPath: string,
57+
packageJsonPath: string,
58+
description = 'path',
59+
): void {
60+
if (!FileUtils.exists(backupPath)) {
61+
Logger.warning(
62+
`Backup package.json not found for ${description}: ${backupPath}. Skipping restore.`,
63+
);
64+
return;
65+
}
66+
67+
Logger.info(`Restoring original package.json for ${description}.`);
68+
fs.renameSync(backupPath, packageJsonPath);
69+
}

0 commit comments

Comments
 (0)