fix: resolve a citation by its number, not its position in the array
A marker names a source by the `number` dedupeSources assigns server-side. Rendering looked it up as sources[n - 1], which works only while the array order and the numbers agree. Nothing breaks that today, but it is an implicit contract across a network boundary: any later filtering or reordering of the list — hiding low-score sources, say — would point citations at the wrong source silently, which is worse than not linking at all. Matching on the number cannot drift. Positional lookup remains as the fallback for a list whose entries carry no number. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
parent
e2444066a0
commit
6dcdf36c81
1 changed files with 17 additions and 3 deletions
|
|
@ -88,6 +88,20 @@ export function wrapTables(html) {
|
|||
.replace(/<\/table>/g, '</table></div>');
|
||||
}
|
||||
|
||||
// A citation marker names a source by its `number`, which dedupeSources assigns
|
||||
// server-side. Resolving it by array position happens to work today because the
|
||||
// two agree, but any future filtering or reordering of the list between the
|
||||
// server and here would silently point citations at the wrong source. Matching
|
||||
// on the number cannot drift.
|
||||
function sourceByNumber(sources, n) {
|
||||
var list = sources || [];
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i] && Number(list[i].number) === Number(n)) return list[i];
|
||||
}
|
||||
// Sources predating the numbering, or a caller passing a bare list.
|
||||
return list[n - 1];
|
||||
}
|
||||
|
||||
export function renderCitationLinks(html, sources, options) {
|
||||
var opts = options || {};
|
||||
return String(html || '').replace(new RegExp(
|
||||
|
|
@ -95,9 +109,9 @@ export function renderCitationLinks(html, sources, options) {
|
|||
'gi'), function (match, tag, cluster) {
|
||||
if (!cluster) return match;
|
||||
var nums = cluster.split(',').map(function (n) { return Number(n.trim()); }).filter(function (n) { return Number.isInteger(n) && n > 0; });
|
||||
if (!nums.length || nums.some(function (n) { return !sources[n - 1]; })) return match;
|
||||
if (!nums.length || nums.some(function (n) { return !sourceByNumber(sources, n); })) return match;
|
||||
return nums.map(function (n) {
|
||||
var source = sources[n - 1];
|
||||
var source = sourceByNumber(sources, n);
|
||||
var title = source ? source.title || source.resource || 'Source' : 'Source';
|
||||
var page = source && (source.page || source.page_number || source.pageNumber);
|
||||
var label = 'Source ' + n + ': ' + title + (page ? ', page ' + page : '');
|
||||
|
|
@ -136,7 +150,7 @@ function parseCitationCluster(cluster) {
|
|||
}
|
||||
|
||||
function allCitationsAvailable(nums, sources) {
|
||||
return nums.length > 0 && nums.every(function(n) { return sources[n - 1]; });
|
||||
return nums.length > 0 && nums.every(function(n) { return sourceByNumber(sources, n); });
|
||||
}
|
||||
|
||||
function formatCitationCluster(nums) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue