Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 59 additions & 29 deletions browse/src/write-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,62 @@ const CLEANUP_SELECTORS = {
],
};

export interface PrettyScreenshotOptions {
scrollTo?: string;
doCleanup: boolean;
hideSelectors: string[];
viewportWidth?: number;
outputPath?: string;
}

function isLikelyScreenshotOutputPath(arg: string): boolean {
return arg.startsWith('/')
|| arg.startsWith('./')
|| arg.startsWith('../')
|| arg.startsWith('~')
|| /\.(png|jpe?g|webp)$/i.test(arg);
}

export function parsePrettyScreenshotArgs(args: string[]): PrettyScreenshotOptions {
const options: PrettyScreenshotOptions = {
doCleanup: false,
hideSelectors: [],
};

for (let i = 0; i < args.length; i++) {
if (args[i] === '--scroll-to' && i + 1 < args.length) {
options.scrollTo = args[++i];
} else if (args[i] === '--cleanup') {
options.doCleanup = true;
} else if (args[i] === '--hide' && i + 1 < args.length) {
const values: string[] = [];
i++;
while (i < args.length && !args[i].startsWith('--')) {
values.push(args[i]);
i++;
}
i--; // Back up since the for loop will increment.

if (!options.outputPath && values.length > 1) {
const last = values[values.length - 1];
if (isLikelyScreenshotOutputPath(last)) {
options.outputPath = values.pop();
}
}
options.hideSelectors.push(...values);
} else if (args[i] === '--width' && i + 1 < args.length) {
options.viewportWidth = parseInt(args[++i], 10);
if (isNaN(options.viewportWidth)) throw new Error('--width must be a number');
} else if (!args[i].startsWith('--')) {
options.outputPath = args[i];
} else {
throw new Error(`Unknown prettyscreenshot flag: ${args[i]}`);
}
}

return options;
}

export async function handleWriteCommand(
command: string,
args: string[],
Expand Down Expand Up @@ -992,35 +1048,9 @@ export async function handleWriteCommand(
}

case 'prettyscreenshot': {
// Parse flags
let scrollTo: string | undefined;
let doCleanup = false;
const hideSelectors: string[] = [];
let viewportWidth: number | undefined;
let outputPath: string | undefined;

for (let i = 0; i < args.length; i++) {
if (args[i] === '--scroll-to' && i + 1 < args.length) {
scrollTo = args[++i];
} else if (args[i] === '--cleanup') {
doCleanup = true;
} else if (args[i] === '--hide' && i + 1 < args.length) {
// Collect all following non-flag args as selectors to hide
i++;
while (i < args.length && !args[i].startsWith('--')) {
hideSelectors.push(args[i]);
i++;
}
i--; // Back up since the for loop will increment
} else if (args[i] === '--width' && i + 1 < args.length) {
viewportWidth = parseInt(args[++i], 10);
if (isNaN(viewportWidth)) throw new Error('--width must be a number');
} else if (!args[i].startsWith('--')) {
outputPath = args[i];
} else {
throw new Error(`Unknown prettyscreenshot flag: ${args[i]}`);
}
}
const prettyOptions = parsePrettyScreenshotArgs(args);
const { scrollTo, doCleanup, hideSelectors, viewportWidth } = prettyOptions;
let { outputPath } = prettyOptions;

// Default output path
if (!outputPath) {
Expand Down
33 changes: 33 additions & 0 deletions browse/test/prettyscreenshot-args.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, expect, test } from 'bun:test';
import { parsePrettyScreenshotArgs } from '../src/write-commands';

describe('parsePrettyScreenshotArgs', () => {
test('treats trailing path after --hide as output path', () => {
const parsed = parsePrettyScreenshotArgs(['--hide', 'header', '/tmp/case-a.png']);

expect(parsed.hideSelectors).toEqual(['header']);
expect(parsed.outputPath).toBe('/tmp/case-a.png');
});

test('keeps multiple trailing --hide selectors when no output path is present', () => {
const parsed = parsePrettyScreenshotArgs(['--hide', 'header', 'footer']);

expect(parsed.hideSelectors).toEqual(['header', 'footer']);
expect(parsed.outputPath).toBeUndefined();
});

test('handles multiple --hide flags with explicit trailing output path', () => {
const parsed = parsePrettyScreenshotArgs(['--hide', 'header', '--hide', 'footer', './shot.webp']);

expect(parsed.hideSelectors).toEqual(['header', 'footer']);
expect(parsed.outputPath).toBe('./shot.webp');
});

test('still honors paths after a later flag', () => {
const parsed = parsePrettyScreenshotArgs(['--hide', 'header', '--cleanup', '/tmp/case-b.png']);

expect(parsed.hideSelectors).toEqual(['header']);
expect(parsed.doCleanup).toBe(true);
expect(parsed.outputPath).toBe('/tmp/case-b.png');
});
});
Loading