← back to Pattern Vault
scripts/add-ai-disclosure.mjs
57 lines
#!/usr/bin/env node
// Add a marketplace-compliant AI-generation disclosure to the `description` of every row in
// all three upload kits. Contrarian gate (2026-07-04) flagged undisclosed AI as a ToS violation
// on Etsy + Creative Market (undisclosed-AI listings get flagged/removed). Idempotent: skips rows
// that already carry the disclosure. All 38 designs are AI-generated (Wallpaper's Back studio).
//
// Usage: node scripts/add-ai-disclosure.mjs
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const DISCLOSURE = 'Created in our studio using AI-assisted generative design tools; each design is human-curated and original.';
const MARK = 'AI-assisted generative design tools'; // idempotency probe
// robust CSV parse + serialize (quoted fields, doubled quotes, embedded commas/newlines)
function parseCsv(s) {
const rows = []; let f = [], cur = '', inq = false;
for (let i = 0; i < s.length; i++) {
const c = s[i];
if (inq) { if (c === '"') { if (s[i + 1] === '"') { cur += '"'; i++; } else inq = false; } else cur += c; }
else if (c === '"') inq = true;
else if (c === ',') { f.push(cur); cur = ''; }
else if (c === '\n') { f.push(cur); rows.push(f); f = []; cur = ''; }
else if (c !== '\r') cur += c;
}
if (cur || f.length) { f.push(cur); rows.push(f); }
return rows.filter((r) => r.length > 1 || r[0] !== '');
}
const q = (v) => { const s = String(v ?? ''); return /[",\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s; };
const kits = {
'kits/spoonflower/listings.csv': 'description',
'kits/etsy/listings.csv': 'description',
'kits/creative-market/listings.csv': 'description',
};
const summary = {};
for (const [rel, col] of Object.entries(kits)) {
const p = path.join(ROOT, rel);
const rows = parseCsv(fs.readFileSync(p, 'utf8'));
const header = rows[0];
const ci = header.indexOf(col);
let added = 0;
for (let r = 1; r < rows.length; r++) {
const d = rows[r][ci] || '';
if (d.includes(MARK)) continue; // already disclosed
rows[r][ci] = (d.trim() + ' ' + DISCLOSURE).trim();
added++;
}
fs.writeFileSync(p, rows.map((r) => r.map(q).join(',')).join('\n') + '\n');
summary[rel] = added;
}
console.log('AI disclosure appended:');
for (const [k, v] of Object.entries(summary)) console.log(` + ${v} rows -> ${k}`);