Skip to content

Commit 1d64043

Browse files
committed
Add explanatory comments for mock ChildProcess pattern
Clarify the purpose and implementation of the mock ChildProcess object used for backward compatibility with the ShadowBinResult interface.
1 parent 6428b5c commit 1d64043

File tree

2 files changed

+24
-16
lines changed

2 files changed

+24
-16
lines changed

src/commands/manifest/cmd-manifest-cdxgen.mts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import type {
1616
CliCommandConfig,
1717
CliCommandContext,
1818
} from '../../utils/meow-with-subcommands.mts'
19-
import type { ChildProcess } from 'node:child_process'
2019

2120
// TODO: Convert yargs to meow.
2221
const toLower = (arg: string) => arg.toLowerCase()
@@ -327,18 +326,10 @@ async function run(
327326
process.exitCode = 1
328327

329328
const result = await runCdxgen(yargv)
330-
// See https://nodejs.org/api/child_process.html#event-exit.
331-
;(result.spawnPromise.process as ChildProcess).on(
332-
'exit',
333-
(code: number | null, signalName: NodeJS.Signals | null) => {
334-
if (signalName) {
335-
process.kill(process.pid, signalName)
336-
} else if (typeof code === 'number') {
337-
// eslint-disable-next-line n/no-process-exit
338-
process.exit(code)
339-
}
340-
},
341-
)
329+
const output = await result.spawnPromise
342330

343-
await result.spawnPromise
331+
// Update process exit code based on cdxgen result.
332+
if (typeof output.code === 'number') {
333+
process.exitCode = output.code
334+
}
344335
}

src/commands/manifest/run-cdxgen.mts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ export async function runCdxgen(argvObj: ArgvObject): Promise<ShadowBinResult> {
125125
const cdxgenPackageSpec = `@cyclonedx/cdxgen@${cdxgenVersion}`
126126
const cdxgenArgs = argvObjectToArray(argvMutable)
127127

128+
// Check if this is a help/version request.
129+
const isHelpRequest = argvMutable['help'] || argvMutable['version']
130+
128131
const result = await runShadowCommand(cdxgenPackageSpec, cdxgenArgs, {
129132
agent,
130133
ipc: {
@@ -137,17 +140,31 @@ export async function runCdxgen(argvObj: ArgvObject): Promise<ShadowBinResult> {
137140
})
138141

139142
// Create fake ShadowBinResult for backward compatibility.
143+
// Note: Help/version requests should always exit with code 0.
144+
const exitCode = result.ok || isHelpRequest ? 0 : (result.code ?? 1)
140145
const stdioResult = {
141146
cmd: 'cdxgen',
142147
args: [] as const,
143-
code: result.ok ? 0 : (result.code ?? 1),
148+
code: exitCode,
144149
signal: null,
145150
stderr: Buffer.from(''),
146151
stdout: Buffer.from(result.ok ? result.data : ''),
147152
}
153+
154+
// Create a mock ChildProcess with event emitter methods for backward compatibility.
155+
// The ShadowBinResult interface expects a ChildProcess, but runShadowCommand doesn't
156+
// return one. This mock provides the minimum EventEmitter interface needed by callers
157+
// while maintaining API compatibility. Each method returns 'this' to support chaining.
158+
const mockProcess = {
159+
on: () => mockProcess,
160+
once: () => mockProcess,
161+
off: () => mockProcess,
162+
removeListener: () => mockProcess,
163+
} as unknown as ChildProcess
164+
148165
const shadowResult: ShadowBinResult = {
149166
spawnPromise: Object.assign(Promise.resolve(stdioResult), {
150-
process: {} as ChildProcess,
167+
process: mockProcess,
151168
stdin: null,
152169
}),
153170
}

0 commit comments

Comments
 (0)