diff --git a/__tests__/cli.spec.ts b/__tests__/cli.spec.ts index 51d5539..35b2e84 100644 --- a/__tests__/cli.spec.ts +++ b/__tests__/cli.spec.ts @@ -119,4 +119,47 @@ describe("cli tests", () => { await expect(main(["node", "lint-md"])).rejects.toThrow("process.exit"); expect(mockExit).toHaveBeenCalledWith(0); }); + + test("rejects file arguments combined with --stdin", async () => { + const runFileLint = jest.fn().mockResolvedValue({ exitCode: 0 }); + const runStdinLint = jest.fn().mockReturnValue({ exitCode: 0 }); + jest.doMock("../src/cli/run-lint", () => ({ + runFileLint, + runStdinLint, + })); + const mockError = jest.spyOn(console, "error").mockImplementation(); + const { runCli } = require("../src/lint-md"); + + process.exitCode = undefined; + runCli(["node", "lint-md", "fixture.md", "--stdin"]); + await new Promise((resolve) => setImmediate(resolve)); + + expect(mockError).toHaveBeenCalledWith( + expect.stringContaining( + "[lint-md] --stdin cannot be used with file arguments." + ) + ); + expect(runStdinLint).not.toHaveBeenCalled(); + expect(runFileLint).not.toHaveBeenCalled(); + expect(process.exitCode).toBe(1); + }); + + test("rejects the -i short form combined with file arguments", async () => { + const runFileLint = jest.fn().mockResolvedValue({ exitCode: 0 }); + const runStdinLint = jest.fn().mockReturnValue({ exitCode: 0 }); + jest.doMock("../src/cli/run-lint", () => ({ + runFileLint, + runStdinLint, + })); + const mockError = jest.spyOn(console, "error").mockImplementation(); + const { runCli } = require("../src/lint-md"); + + process.exitCode = undefined; + runCli(["node", "lint-md", "-i", "fixture.md"]); + await new Promise((resolve) => setImmediate(resolve)); + + expect(runStdinLint).not.toHaveBeenCalled(); + expect(runFileLint).not.toHaveBeenCalled(); + expect(process.exitCode).toBe(1); + }); }); diff --git a/src/cli/cli-error.ts b/src/cli/cli-error.ts index a17eb59..02cb84a 100644 --- a/src/cli/cli-error.ts +++ b/src/cli/cli-error.ts @@ -4,7 +4,8 @@ export type CliErrorCode = | "CONFIG_NOT_FOUND" | "CONFIG_INVALID" | "INVALID_THREADS" - | "INVALID_MAX_FILE_SIZE"; + | "INVALID_MAX_FILE_SIZE" + | "CONFLICTING_INPUT"; export class CliError extends Error { constructor( diff --git a/src/lint-md.ts b/src/lint-md.ts index 8a2a18b..18ca197 100644 --- a/src/lint-md.ts +++ b/src/lint-md.ts @@ -76,6 +76,15 @@ export const createProgram = (): Command => { const isFixMode = Boolean(fix); const isDev = Boolean(dev); + // Fail before touching stdin or the file list so neither input mode + // starts on a command that mixes both. + if (stdin && files.length > 0) { + throw new CliError( + "CONFLICTING_INPUT", + "[lint-md] --stdin cannot be used with file arguments." + ); + } + if (isDev) { console.log(`dev -- version: ${version}, ${new Date().toString()}`); }