Skip to content

Commit d82feef

Browse files
multiple codemod same time
1 parent 1b071d1 commit d82feef

File tree

2 files changed

+78
-17
lines changed

2 files changed

+78
-17
lines changed

utils/src/logger.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,38 @@ describe('logger', { concurrency: true }, () => {
9292
t.assert.snapshot(stdout);
9393
assert.equal(code, 0);
9494
});
95+
96+
it('should handle multiple codemods with different names correctly', async () => {
97+
const { code, stdout } = await spawnPromisified(
98+
execPath,
99+
[
100+
'--no-warnings',
101+
'--experimental-strip-types',
102+
'-e',
103+
dedent`
104+
import { logger, setCodemodName } from './logger.ts';
105+
106+
// Simulate first codemod
107+
setCodemodName('codemod-a');
108+
logger('/tmp/file1.js', 'log', 'Message from codemod A');
109+
110+
// Simulate second codemod (this would previously overwrite the name)
111+
logger('/tmp/file2.js', 'log', 'Message from codemod B', 'codemod-b');
112+
113+
// Another message from first codemod (should still show as codemod-a)
114+
logger('/tmp/file3.js', 'log', 'Another message from codemod A');
115+
`,
116+
],
117+
{
118+
cwd: import.meta.dirname,
119+
},
120+
);
121+
122+
// Should show both codemod names in output
123+
assert(stdout.includes('[Codemod: codemod-a]'));
124+
assert(stdout.includes('[Codemod: codemod-b]'));
125+
assert(stdout.includes('Message from codemod A'));
126+
assert(stdout.includes('Message from codemod B'));
127+
assert.equal(code, 0);
128+
});
95129
});

utils/src/logger.ts

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,26 @@ import process from 'node:process';
22

33
type LogMsg = string;
44
type LogType = 'error' | 'log' | 'warn';
5-
type FileLog = { msg: LogMsg; type: LogType };
5+
type FileLog = { msg: LogMsg; type: LogType; codemodName: string };
66
type Source = URL['pathname'];
77

8-
let codemodName = 'nodjs-codemod';
8+
let defaultCodemodName = 'nodjs-codemod';
99

1010
/**
11-
* Set the codemod name for logging output
11+
* Set the default codemod name for logging output
1212
*/
1313
export const setCodemodName = (name: string) => {
14-
codemodName = name;
14+
defaultCodemodName = name;
1515
};
1616

1717
/**
1818
* Collect log entries and report them at the end, collated by source module.
1919
*/
20-
export const logger = (source: Source, type: LogType, msg: LogMsg) => {
20+
export const logger = (source: Source, type: LogType, msg: LogMsg, codemodName?: string) => {
21+
const name = codemodName ?? defaultCodemodName;
2122
const fileLog = new Set<FileLog>(logs.has(source) ? logs.get(source) : []);
2223

23-
fileLog.add({ msg, type });
24+
fileLog.add({ msg, type, codemodName: name });
2425
logs.set(source, fileLog);
2526
};
2627

@@ -34,19 +35,45 @@ process.once('beforeExit', emitLogs);
3435
function emitLogs() {
3536
let hasError = false;
3637

37-
for (const [sourceFile, fileLog] of logs.entries()) {
38-
console.log(`[Codemod: ${codemodName}]:`, sourceFile);
39-
for (const { msg, type } of fileLog) {
40-
console[type](' •', msg);
41-
if (type === 'error') hasError = true;
38+
// Group logs by codemod name first, then by source file
39+
const logsByCodemod = new Map<string, Map<Source, Set<FileLog>>>();
40+
41+
for (const [sourceFile, fileLogs] of logs.entries()) {
42+
for (const fileLog of fileLogs) {
43+
if (!logsByCodemod.has(fileLog.codemodName)) {
44+
logsByCodemod.set(fileLog.codemodName, new Map());
45+
}
46+
const codemodLogs = logsByCodemod.get(fileLog.codemodName)!;
47+
if (!codemodLogs.has(sourceFile)) {
48+
codemodLogs.set(sourceFile, new Set());
49+
}
50+
codemodLogs.get(sourceFile)!.add(fileLog);
4251
}
4352
}
4453

45-
if (hasError) {
46-
console.error(`[Codemod: ${codemodName}]: migration incomplete!`);
47-
process.exitCode = 1;
48-
} else {
49-
process.exitCode = 0;
50-
console.log(`[Codemod: ${codemodName}]: migration complete!`);
54+
for (const [codemodName, codemodLogs] of logsByCodemod.entries()) {
55+
for (const [sourceFile, fileLogs] of codemodLogs.entries()) {
56+
console.log(`[Codemod: ${codemodName}]:`, sourceFile);
57+
for (const { msg, type } of fileLogs) {
58+
console[type](' •', msg);
59+
if (type === 'error') hasError = true;
60+
}
61+
}
62+
63+
if (hasError) {
64+
console.error(`[Codemod: ${codemodName}]: migration incomplete!`);
65+
} else {
66+
console.log(`[Codemod: ${codemodName}]: migration complete!`);
67+
}
68+
hasError = false; // Reset for next codemod
5169
}
70+
71+
// Set overall exit code based on any errors
72+
process.exitCode = Array.from(logsByCodemod.values())
73+
.some(codemodLogs =>
74+
Array.from(codemodLogs.values())
75+
.some(fileLogs =>
76+
Array.from(fileLogs).some(log => log.type === 'error')
77+
)
78+
) ? 1 : 0;
5279
}

0 commit comments

Comments
 (0)