squint-cli
Version:
Squint makes visual reviews of web app releases easy
149 lines (132 loc) • 4.16 kB
text/typescript
import path from 'path'
import _ from 'lodash'
import puppeteer, { ScreenshotOptions } from 'puppeteer'
import { formatHelp, parseCliArgs } from './cli'
export type puppeteerLaunchMode =
| {
type: 'connect'
options: Parameters<typeof puppeteer.connect>[0]
}
| {
type: 'launch'
options?: Parameters<typeof puppeteer.launch>[0]
}
export type Config = {
width: number
height: number
includeHash: boolean
includeSearchQuery: boolean
shouldVisit?: string
trailingSlashMode: 'preserve' | 'remove' | 'add'
puppeteerLaunchMode: puppeteerLaunchMode
puppeteerPagePoolMax: number
maxDepth: number
outDir: string
outFile: string
afterGoto?: string
afterPage?: string
selector?: string
selectorJs?: string
singlePage: boolean
pathsFile?: string
screenshotOptions: ScreenshotOptions
saveAll: boolean
// Positional arguments
command: string
oldUrl: string
newUrl: string
crawlUrl: string
screenshotUrl: string
}
export const defaultConfig = {
width: 1280,
height: 800,
includeHash: false,
includeSearchQuery: false,
trailingSlashMode: 'preserve',
saveAll: false,
maxDepth: Infinity,
puppeteerLaunchMode: {
type: 'launch' as const,
options: {
headless: true,
},
},
puppeteerPagePoolMax: 10,
outDir: '.squint',
screenshotOptions: {},
}
function isEmptyArgument(val: any): boolean {
return !_.isString(val) || val.length < 1
}
export function parseConfig() {
const args = parseCliArgs()
if (args['--help']) {
console.error(formatHelp(defaultConfig))
process.exit(0)
}
const command = args['_'][0]
const outDir = args['--out-dir'] ?? defaultConfig.outDir
const defaultOutFile =
command === 'compare'
? path.join(outDir, 'diff.png')
: path.join(outDir, 'screenshot.png')
const config: Config = {
width: args['--width'] ?? defaultConfig.width,
height: args['--height'] ?? defaultConfig.height,
includeHash: args['--include-hash'] ?? defaultConfig.includeHash,
includeSearchQuery:
args['--include-search-query'] ?? defaultConfig.includeSearchQuery,
trailingSlashMode:
args['--trailing-slash-mode'] ?? defaultConfig.trailingSlashMode,
shouldVisit: args['--should-visit'],
maxDepth: args['--max-depth'] ?? defaultConfig.maxDepth,
outDir,
outFile: args['--out-file'] ?? defaultOutFile,
puppeteerLaunchMode: {
type:
args['--puppeteer-launch-mode'] ??
defaultConfig.puppeteerLaunchMode.type,
options:
args['--puppeteer-launch-options'] ??
defaultConfig.puppeteerLaunchMode.options,
} as Config['puppeteerLaunchMode'],
puppeteerPagePoolMax:
args['--puppeteer-page-pool-max'] ?? defaultConfig.puppeteerPagePoolMax,
afterGoto: args['--after-goto'],
afterPage: args['--after-page'],
selector: args['--selector'],
selectorJs: args['--selector-js'],
singlePage: args['--single-page'] ?? false,
saveAll: args['--save-all'] ?? false,
pathsFile: args['--paths-file'],
screenshotOptions:
args['--screenshot-options'] ?? defaultConfig.screenshotOptions,
// Positional arguments
command,
oldUrl: args['_'][1],
newUrl: args['_'][2],
crawlUrl: args['_'][1],
screenshotUrl: args['_'][1],
}
if (config.command === 'crawl' && isEmptyArgument(config.screenshotUrl)) {
throw new Error(`Command crawl missing a <url> argument`)
}
if (config.command === 'screenshot' && isEmptyArgument(config.crawlUrl)) {
throw new Error(`Command screenshot missing a <url> argument`)
}
if (config.command === 'compare' && isEmptyArgument(config.oldUrl)) {
throw new Error(`Command compare missing <oldUrl> argument`)
}
if (config.command === 'compare' && isEmptyArgument(config.newUrl)) {
throw new Error(`Command compare missing <newUrl> argument`)
}
if (config.command === 'compare' && !config.singlePage) {
const oldPath = new URL(config.oldUrl).pathname
const newPath = new URL(config.newUrl).pathname
if (oldPath !== newPath) {
throw new Error(`Mismatch between url paths detected!`)
}
}
return config
}