From f7d29ac32611cd4f5208a9dbef13bec604c44156 Mon Sep 17 00:00:00 2001 From: Mark Rapson Date: Sat, 24 Oct 2026 20:38:59 +0100 Subject: [PATCH] Exclude empty and zero content references --- CHANGELOG.md | 2 +- src/data/content-references.js | 3 ++- test/content-references.test.js | 39 +++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc90577..56a103e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file. ### Fixed -- Font reference indexing handles HTML-encoded quotes and excludes built-in fonts and generic fallbacks. A one-time migration rebuilds font references for all slides and template defaults without changing content or other reference types. +- Font reference indexing handles HTML-encoded quotes and excludes built-in fonts and generic fallbacks. Empty and zero item selections are excluded from reference indexing. A one-time migration rebuilds font references for all slides and template defaults without changing content or other reference types. ## 2.19.0 - 2026-10-24 diff --git a/src/data/content-references.js b/src/data/content-references.js index 096f734..49e6ef3 100644 --- a/src/data/content-references.js +++ b/src/data/content-references.js @@ -30,9 +30,10 @@ function getFontFamilyCandidates(value) { function addReference(references, seen, ownerKey, referenceType, value) { let referenceValue = String(value === undefined || value === null ? '' : value).trim(); + if (!referenceValue || referenceValue === '0') return; if (['api-request', 'rss-feed', 'timetable-group', 'weather-location'].includes(referenceType)) { const numericValue = Number(referenceValue); - if (!Number.isFinite(numericValue)) return; + if (!Number.isFinite(numericValue) || numericValue === 0) return; referenceValue = String(numericValue); } if (referenceType === 'font-family') { diff --git a/test/content-references.test.js b/test/content-references.test.js index 6da12a9..253660a 100644 --- a/test/content-references.test.js +++ b/test/content-references.test.js @@ -120,4 +120,43 @@ test('content references omit built-in font stacks but retain managed font famil assert.deepEqual(references.map(reference => [reference.owner_key, reference.reference_value]), [ ['managed', 'ubuntu regular'] ]); +}); + +test('content references omit zero and empty item selections for every typed reference field', () => { + const fields = ['source_id', 'feed_id', 'timetable_group_id', 'weather_location_id', 'weather_icon_set_id']; + for (const field of fields) { + for (const value of [0, '0', ' 0 ', '', ' ', null, undefined]) { + assert.deepEqual(collectContentReferences('slide', 117, { empty: { [field]: value } }), [], field + ': ' + String(value)); + } + } + for (const field of fields.slice(0, -1)) { + for (const value of ['00', '0.0', '-0']) { + assert.deepEqual(collectContentReferences('template', 42, { empty: { [field]: value } }), [], field + ': ' + value); + } + } +}); + +test('content reference replacement removes stored zero selections while preserving valid references', async () => { + const calls = []; + const connection = { + async query(sql, params) { + calls.push([sql, params]); + if (sql.startsWith('SELECT id, owner_key')) { + return [[ + { id: 101, owner_key: 'api', reference_type: 'api-request', reference_value: '0' }, + { id: 102, owner_key: 'feed', reference_type: 'rss-feed', reference_value: '8' } + ]]; + } + return [{}]; + } + }; + + await replaceContentReferences(connection, 'slide', 117, { + api: { source_id: 0 }, + feed: { feed_id: 8 } + }); + + const deletion = calls.find(([sql]) => sql.startsWith('DELETE FROM c_content_references')); + assert.deepEqual(deletion[1], ['slide', 117, [101]]); + assert.ok(!calls.some(([sql]) => sql.startsWith('INSERT'))); }); \ No newline at end of file