← back to Tk10630 Sku Suffix Canary

draft-versa-fix.mjs

55 lines

// Build the Versa-leak fix DRAFT (no writes). Gathers every versa-handle product,
// computes new handle (strip '-versa-designed-surfaces') + collision check + 301
// redirect, and the alt-text rewrite ('Versa Designed Surfaces' -> 'Hollywood
// Wallcoverings'). Emits a plan JSON + a pending-approval memo. READ-ONLY on Shopify.
import { gql } from './shopify.mjs';
import { writeFileSync } from 'node:fs';

// 1) collect all versa-handle products (light query paginates fine)
const prods = [];
let cursor = null;
while (true) {
  const q = `query($c:String){ products(first:100, query:"vendor:\\"Hollywood Wallcoverings\\" handle:*versa*", after:$c){
    pageInfo{ hasNextPage endCursor }
    nodes{ id handle status onlineStoreUrl images(first:20){ nodes{ id altText } } } } }`;
  const { data } = await gql(q, { c: cursor });
  prods.push(...data.products.nodes);
  if (!data.products.pageInfo.hasNextPage) break;
  cursor = data.products.pageInfo.endCursor;
}

// 2) build a set of ALL existing Hollywood handles to detect rename collisions
const existing = new Set();
cursor = null;
while (true) {
  const q = `query($c:String){ products(first:250, query:"vendor:\\"Hollywood Wallcoverings\\"", after:$c){ pageInfo{ hasNextPage endCursor } nodes{ handle } } }`;
  const { data } = await gql(q, { c: cursor });
  for (const n of data.products.nodes) existing.add(n.handle);
  if (!data.products.pageInfo.hasNextPage) break;
  cursor = data.products.pageInfo.endCursor;
}

const plan = [];
let collisions = 0, altFixes = 0;
for (const p of prods) {
  let base = p.handle.replace(/-versa-designed-surfaces$/,'').replace(/-versa-designed-surfaces/,'');
  let newHandle = base, n = 2;
  while (newHandle !== p.handle && (existing.has(newHandle))) { newHandle = `${base}-${n++}`; collisions++; }
  const altChanges = p.images.nodes
    .filter(im => /versa/i.test(im.altText || ''))
    .map(im => ({ imageId: im.id, from: im.altText, to: im.altText.replace(/versa\s*designed\s*surfaces/ig, 'Hollywood Wallcoverings').replace(/\|\s*versa/ig, '| Hollywood Wallcoverings') }));
  altFixes += altChanges.length;
  plan.push({ id: p.id, status: p.status, from: p.handle, to: newHandle, url: p.onlineStoreUrl, altChanges });
}

writeFileSync('versa-fix-plan.json', JSON.stringify(plan, null, 0));
const active = plan.filter(p => p.status === 'ACTIVE');
console.log(JSON.stringify({
  products: plan.length, active: active.length,
  handle_renames: plan.filter(p => p.from !== p.to).length,
  rename_collisions_suffixed: collisions,
  alt_text_rewrites: altFixes,
  redirects_needed: plan.filter(p => p.status === 'ACTIVE' && p.from !== p.to).length,
}, null, 2));
console.log('sample:', plan.slice(0, 4).map(p => `${p.from} -> ${p.to} (+${p.altChanges.length} alt)`).join('\n  '));