chromancer
Version:
A powerful command-line interface for automating Chrome browser using Playwright. Perfect for web scraping, automation, testing, and browser workflows.
198 lines (197 loc) ⢠7.75 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@oclif/core");
const base_js_1 = require("../base.js");
const selectors_js_1 = require("../utils/selectors.js");
const evaluation_js_1 = require("../utils/evaluation.js");
class Store extends base_js_1.BaseCommand {
static description = 'Store values from page elements or evaluations for later use';
static examples = [
'<%= config.bin %> <%= command.id %> --selector "#price" --as "originalPrice"',
'<%= config.bin %> <%= command.id %> --eval "document.title" --as "pageTitle"',
'<%= config.bin %> <%= command.id %> --selector "#username" --as "username" --property "value"',
'<%= config.bin %> <%= command.id %> --cookies --as "sessionCookies"',
'<%= config.bin %> <%= command.id %> --list',
'<%= config.bin %> <%= command.id %> --clear',
];
static flags = {
...base_js_1.BaseCommand.baseFlags,
selector: core_1.Flags.string({
char: 's',
description: 'CSS selector of element to store value from',
exclusive: ['eval', 'list', 'clear', 'cookies'],
}),
eval: core_1.Flags.string({
char: 'e',
description: 'JavaScript expression to evaluate and store',
exclusive: ['selector', 'list', 'clear', 'cookies'],
}),
cookies: core_1.Flags.boolean({
description: 'Store all cookies',
exclusive: ['selector', 'eval', 'list', 'clear'],
}),
as: core_1.Flags.string({
char: 'a',
description: 'Variable name to store the value as',
dependsOn: ['selector', 'eval', 'cookies'],
}),
property: core_1.Flags.string({
char: 'p',
description: 'Element property to store (default: textContent)',
default: 'textContent',
dependsOn: ['selector'],
}),
attribute: core_1.Flags.string({
description: 'Element attribute to store',
exclusive: ['property'],
dependsOn: ['selector'],
}),
list: core_1.Flags.boolean({
description: 'List all stored values',
exclusive: ['selector', 'eval', 'clear', 'cookies'],
}),
clear: core_1.Flags.boolean({
description: 'Clear all stored values',
exclusive: ['selector', 'eval', 'list', 'cookies'],
}),
json: core_1.Flags.boolean({
description: 'Output stored values as JSON',
dependsOn: ['list'],
}),
};
// Static storage that persists across command invocations
static storage = {};
async run() {
const { flags } = await this.parse(Store);
// Handle list and clear operations without Chrome connection
if (flags.list) {
this.listStoredValues(flags.json);
return;
}
if (flags.clear) {
this.clearStoredValues();
return;
}
// For other operations, connect to Chrome
await this.connectToChrome(flags.port, flags.host, flags.launch, flags.profile, flags.headless, flags.verbose, flags.keepOpen);
if (!this.page) {
this.error('Failed to connect to Chrome');
}
await this.executeCommand(this.page, flags);
}
async executeCommand(page, flags) {
// Ensure chromancer namespace exists in the page
await page.evaluate(`
if (typeof window.chromancer === 'undefined') {
window.chromancer = { stored: {} };
} else if (typeof window.chromancer.stored === 'undefined') {
window.chromancer.stored = {};
}
`);
// Inject existing stored values into the page
for (const [key, value] of Object.entries(Store.storage)) {
await page.evaluate(`
window.chromancer.stored["${key}"] = ${JSON.stringify(value)};
`);
}
let value;
if (flags.selector) {
// Store from element
try {
this.log(`š Looking for element: ${flags.selector}`);
const element = await (0, selectors_js_1.waitForElement)(page, flags.selector, {
timeout: 5000,
state: 'attached'
});
if (flags.attribute) {
// Get attribute value
value = await element.getAttribute(flags.attribute);
this.logVerbose(`Getting attribute "${flags.attribute}"`);
}
else {
// Get property value
value = await element.evaluate((el, prop) => {
return el[prop];
}, flags.property);
this.logVerbose(`Getting property "${flags.property}"`);
}
}
catch (error) {
if (error.name === 'TimeoutError') {
this.error(`Element not found: ${flags.selector}`);
}
throw error;
}
}
else if (flags.eval) {
// Store from evaluation
this.log(`š§ Evaluating expression...`);
value = await (0, evaluation_js_1.safeEvaluate)(page, flags.eval);
}
else if (flags.cookies) {
// Store cookies
this.log(`šŖ Getting cookies...`);
value = await page.context().cookies();
}
if (!flags.as) {
this.error('Variable name required. Use --as flag to specify a name');
}
// Store the value
Store.storage[flags.as] = value;
// Also store in the page context
await page.evaluate(`
window.chromancer.stored["${flags.as}"] = ${JSON.stringify(value)};
`);
this.log(`ā
Stored value as "${flags.as}": ${this.formatValue(value)}`);
// Log storage info if verbose
if (flags.verbose) {
this.logVerbose('Storage info', {
variable: flags.as,
type: typeof value,
isArray: Array.isArray(value),
totalStored: Object.keys(Store.storage).length,
});
}
}
formatValue(value) {
if (typeof value === 'string') {
return value.length > 100 ? `"${value.substring(0, 100)}..."` : `"${value}"`;
}
if (typeof value === 'object') {
const str = JSON.stringify(value);
return str.length > 100 ? str.substring(0, 100) + '...' : str;
}
return String(value);
}
listStoredValues(json = false) {
if (Object.keys(Store.storage).length === 0) {
this.log('ā No values stored');
return;
}
if (json) {
// Output as JSON for scripting
console.log(JSON.stringify(Store.storage, null, 2));
}
else {
this.log('š¦ Stored values:');
for (const [key, value] of Object.entries(Store.storage)) {
this.log(` ${key}: ${this.formatValue(value)}`);
}
this.log(`\nš Total: ${Object.keys(Store.storage).length} value(s)`);
}
}
clearStoredValues() {
const count = Object.keys(Store.storage).length;
Store.storage = {};
this.log(`ā
Cleared all stored values (${count} values removed)`);
}
// Public method to access storage from other commands
static getStoredValue(key) {
return Store.storage[key];
}
// Public method to get all stored values
static getAllStoredValues() {
return { ...Store.storage };
}
}
exports.default = Store;