Files
stef-openclaw-skills/skills/amazon-shopping/src/product-metrics.ts
T

63 lines
1.9 KiB
TypeScript

import type { ProductSearchResult, ProductSpec } from "./types.js";
function parseDimensionNumber(text: string): number | undefined {
const match = text.match(/([0-9]+(?:\.[0-9]+)?)/);
return match ? Number(match[1]) : undefined;
}
function isOverallWidthSpec(spec: ProductSpec): boolean {
const name = spec.name.toLowerCase();
if (/seat|arm|door|package|box|back|cushion/.test(name)) {
return false;
}
return /width|dimensions?/.test(name);
}
function widthFromSpec(spec: ProductSpec): number | undefined {
if (!isOverallWidthSpec(spec)) {
return undefined;
}
const name = spec.name.toLowerCase();
const value = spec.value;
const labeledWidth = value.match(/([0-9]+(?:\.[0-9]+)?)\s*(?:"|in(?:ches?)?)?\s*W\b/i);
if (labeledWidth) {
return Number(labeledWidth[1]);
}
if (/width/.test(name)) {
return parseDimensionNumber(value);
}
const orderMatch = name.match(/\b([dwh])\s*x\s*([dwh])(?:\s*x\s*([dwh]))?\b/i);
if (orderMatch) {
const order = orderMatch.slice(1).filter(Boolean).map((part) => part.toLowerCase());
const widthIndex = order.indexOf("w");
const values = value.match(/[0-9]+(?:\.[0-9]+)?/g)?.map(Number) ?? [];
if (widthIndex >= 0 && values[widthIndex] !== undefined) {
return values[widthIndex];
}
}
return undefined;
}
export function extractWidthInches(product: ProductSearchResult): number | undefined {
for (const spec of product.specs) {
const width = widthFromSpec(spec);
if (width !== undefined) {
return width;
}
}
const titleMatch = product.title.match(/\b([0-9]+(?:\.[0-9]+)?)\s*(?:["”]|in(?:ch(?:es)?)?)\b/i);
return titleMatch ? Number(titleMatch[1]) : undefined;
}
export function formatWidthInches(width: number | undefined): string {
if (width === undefined) {
return "unknown";
}
return `${Number.isInteger(width) ? width.toFixed(0) : width.toFixed(1)}"`;
}