diff --git a/modules/validation.js b/modules/validation.js index 72f2309..79c181d 100644 --- a/modules/validation.js +++ b/modules/validation.js @@ -44,33 +44,37 @@ export const ATTACHMENT_WARN_SIZE = 5 * 1024 * 1024; /** Total attachment size warning threshold (10 MB). */ export const ATTACHMENT_TOTAL_WARN_SIZE = 10 * 1024 * 1024; -/** - * Analyse an import payload against existing templates. - * Returns { valid: object[], invalid: number, duplicates: Map } - * where duplicates maps lowercase-name to the most recent import entry that collides - * with either an existing template or another imported template. - */ -export function analyseImport(importedTemplates, existingTemplates) { - const seenNames = new Map( - existingTemplates.map((t) => [t.name.toLowerCase(), t]) - ); - - const valid = []; - let invalid = 0; +/** + * Analyse an import payload against existing templates. + * Returns { valid: object[], invalid: number, duplicates: Map } + * where duplicates maps lowercase-name to the most recent import entry that collides + * with either an existing template or another imported template. + */ +export function analyseImport(importedTemplates, existingTemplates) { + // Tracks all names seen so far: pre-seeded with existing template names + // for storage-level dedup, then extended with each processed import for + // intra-import dedup (so two imported templates with the same name both + // land in `duplicates`). + const allSeenNames = new Map( + existingTemplates.map((t) => [t.name.toLowerCase(), t]) + ); + + const valid = []; // Structurally valid templates — includes duplicates. + let invalid = 0; const duplicates = new Map(); for (const t of importedTemplates) { if (!t || typeof t.name !== "string" || !t.name.trim()) { invalid++; continue; - } - const key = t.name.trim().toLowerCase(); - if (seenNames.has(key)) { - duplicates.set(key, t); - } - seenNames.set(key, t); - valid.push(t); - } - - return { valid, invalid, duplicates }; -} + } + const key = t.name.trim().toLowerCase(); + if (allSeenNames.has(key)) { + duplicates.set(key, t); + } + allSeenNames.set(key, t); + valid.push(t); // Always included; callers must consult `duplicates` for merge logic. + } + + return { valid, invalid, duplicates }; +}