const { PrismaClient } = require('@prisma/client') const prisma = new PrismaClient() function isArrayString(str) { const trimmed = (str || '').trim() if (!trimmed.startsWith('[') || !trimmed.endsWith(']')) return false try { const parsed = JSON.parse(trimmed) return Array.isArray(parsed) } catch { return false } } function normalizeOptionValue(option) { let cleaned = (option || '').trim() if (!cleaned) return '' try { if ( (cleaned.startsWith('"') && cleaned.endsWith('"')) || (cleaned.startsWith("'") && cleaned.endsWith("'")) ) { const parsed = JSON.parse(cleaned) if (typeof parsed === 'string') { cleaned = parsed.trim() } } } catch { // ignore parse errors } cleaned = cleaned.replace(/\\+"/g, '"').replace(/\\'/g, "'") cleaned = cleaned.replace(/["'`“”]/g, '') cleaned = cleaned.trim() if (cleaned.startsWith('\\') && cleaned.endsWith('\\')) { cleaned = cleaned.slice(1, -1).trim() } return cleaned.trim() } function stripLooseBrackets(value) { let result = (value || '').trim() let guard = 0 while (result.startsWith('[') && result.endsWith(']') && guard < 5) { const inner = result.slice(1, -1).trim() if (!inner || inner === result) { break } result = inner guard += 1 } return result } function extractLooseArrayOptions(option) { let trimmed = (option || '').trim() if (!trimmed.startsWith('[') || !trimmed.endsWith(']')) return null let inner = trimmed let safeGuard = 0 while (inner.startsWith('[') && inner.endsWith(']') && safeGuard < 5) { const next = inner.slice(1, -1).trim() if (!next || next === inner) { break } inner = next safeGuard += 1 } if (!inner) return [] const segments = inner.split(/[,,]/).map(seg => normalizeOptionValue(seg)).filter(Boolean) if (segments.length > 1) { return segments } const single = normalizeOptionValue(inner) return single ? [single] : null } function sanitizeOptions(optionsStatic) { if (!optionsStatic) return [] const result = new Set() const pushOption = (value) => { const normalized = stripLooseBrackets(normalizeOptionValue(value)) if (normalized && !isArrayString(normalized)) { result.add(normalized) } } try { const parsed = JSON.parse(optionsStatic) if (Array.isArray(parsed)) { parsed.forEach(opt => { const optStr = String(opt || '').trim() if (!optStr) return const loose = extractLooseArrayOptions(optStr) if (loose && loose.length) { loose.forEach(pushOption) return } if (isArrayString(optStr)) { try { const nested = JSON.parse(optStr) if (Array.isArray(nested)) { nested.forEach(item => pushOption(String(item))) return } } catch { // ignore } } pushOption(optStr) }) return Array.from(result) } } catch { // ignored } optionsStatic .split('\n') .map(line => line.trim()) .filter(Boolean) .forEach(line => { const loose = extractLooseArrayOptions(line) if (loose && loose.length) { loose.forEach(pushOption) } else { pushOption(line) } }) return Array.from(result) } async function main() { const fields = await prisma.uploadField.findMany({ where: { optionsStatic: { not: null, }, }, select: { id: true, key: true, label: true, optionsStatic: true, }, }) let updated = 0 for (const field of fields) { const sanitized = sanitizeOptions(field.optionsStatic) const sanitizedJson = JSON.stringify(sanitized) const currentTrimmed = (field.optionsStatic || '').trim() if (sanitizedJson && sanitizedJson !== currentTrimmed) { await prisma.uploadField.update({ where: { id: field.id }, data: { optionsStatic: sanitizedJson }, }) updated += 1 console.log(`[Cleanup] Updated ${field.key} (${field.label}) -> ${sanitizedJson}`) } } console.log(`Cleanup finished. Updated ${updated} field(s).`) } main() .catch((error) => { console.error('Cleanup failed:', error) process.exitCode = 1 }) .finally(async () => { await prisma.$disconnect() })