strip-sms-optout.mjs
1 /** 2 * Strip opt-out spintax from SMS templates for countries where it's not legally required. 3 * Required (keep opt-out): US, CA, KR 4 * Not required (remove opt-out): everything else 5 */ 6 import { readFileSync, writeFileSync } from 'node:fs'; 7 import { resolve, dirname } from 'node:path'; 8 import { fileURLToPath } from 'node:url'; 9 10 const __dirname = dirname(fileURLToPath(import.meta.url)); 11 const root = resolve(__dirname, '..'); 12 13 const requirements = JSON.parse( 14 readFileSync(resolve(root, 'data/compliance/requirements.json'), 'utf8') 15 ); 16 17 // Countries where opt-out IS required in body 18 const REQUIRED = new Set( 19 Object.entries(requirements) 20 .filter(([k, v]) => !k.startsWith('_') && v?.sms?.requiresOptOutInBody === true) 21 .map(([k]) => k) 22 ); 23 24 console.log('Opt-out REQUIRED (keep):', [...REQUIRED].join(', ')); 25 26 // All SMS template files 27 const SMS_FILES = [ 28 { country: 'AU', file: 'data/templates/AU/sms.json' }, 29 { country: 'NZ', file: 'data/templates/NZ/sms.json' }, 30 { country: 'GB', file: 'data/templates/GB/sms.json' }, 31 { country: 'IE', file: 'data/templates/IE/sms.json' }, 32 { country: 'CA', file: 'data/templates/CA/sms.json' }, 33 { country: 'US', file: 'data/templates/US/sms.json' }, 34 { country: 'IN', file: 'data/templates/IN/sms.json' }, 35 { country: 'IN', file: 'data/templates/IN/hi/sms.json' }, 36 { country: 'JP', file: 'data/templates/JP/ja/sms.json' }, 37 { country: 'KR', file: 'data/templates/KR/ko/sms.json' }, 38 { country: 'DE', file: 'data/templates/DE/de/sms.json' }, 39 { country: 'FR', file: 'data/templates/FR/fr/sms.json' }, 40 { country: 'IT', file: 'data/templates/IT/it/sms.json' }, 41 { country: 'MX', file: 'data/templates/MX/es/sms.json' }, 42 { country: 'NL', file: 'data/templates/NL/nl/sms.json' }, 43 { country: 'SE', file: 'data/templates/SE/sv/sms.json' }, 44 { country: 'DK', file: 'data/templates/DK/da/sms.json' }, 45 { country: 'PL', file: 'data/templates/PL/pl/sms.json' }, 46 { country: 'ID', file: 'data/templates/ID/id/sms.json' }, 47 { country: 'ZA', file: 'data/templates/ZA/sms.json' }, 48 ]; 49 50 // Matches trailing opt-out spintax: a space + {options containing STOP or stop} 51 // The opt-out block is always the last {...} group in the body_spintax 52 const OPT_OUT_RE = /\s+\{[^{}]*(?:STOP|stop|停止|거부)[^{}]*\}$/u; 53 54 let changed = 0; 55 let skipped = 0; 56 57 for (const { country, file } of SMS_FILES) { 58 const filePath = resolve(root, file); 59 60 if (REQUIRED.has(country)) { 61 console.log(`[${country}] SKIP — opt-out required`); 62 skipped++; 63 continue; 64 } 65 66 const data = JSON.parse(readFileSync(filePath, 'utf8')); 67 let modified = false; 68 69 for (const tmpl of data.templates) { 70 const orig = tmpl.body_spintax; 71 const stripped = orig.replace(OPT_OUT_RE, '').trimEnd(); 72 if (stripped !== orig) { 73 tmpl.body_spintax = stripped; 74 modified = true; 75 console.log(` [${country}] ${tmpl.id}: removed opt-out`); 76 } else { 77 console.log(` [${country}] ${tmpl.id}: no opt-out found`); 78 } 79 } 80 81 if (modified) { 82 writeFileSync(filePath, `${JSON.stringify(data, null, ' ')}\n`, 'utf8'); 83 changed++; 84 } 85 } 86 87 console.log(`\nDone. ${changed} files modified, ${skipped} skipped (opt-out required).`);