fix: cycle references resolve to Label (symbol) instead of empty
When a {id:description} reference forms a cycle, the back-reference
now expands to 'Label (symbol)' rather than being stripped.
So pound ↔ dickload renders as 'See dickload (dl)' and 'See pound (lb)'.
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
"symbol": "lb",
|
"symbol": "lb",
|
||||||
"group": "dickloads",
|
"group": "dickloads",
|
||||||
"toBase": 0.038,
|
"toBase": 0.038,
|
||||||
"description": "{dickload:description}"
|
"description": "My description is {dickload:description}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "dickload",
|
"id": "dickload",
|
||||||
|
|||||||
@@ -15,14 +15,13 @@ import type { Unit, Group } from './types';
|
|||||||
* Replace {id:description} tokens with a sentinel \x00DESC:id\x00
|
* Replace {id:description} tokens with a sentinel \x00DESC:id\x00
|
||||||
* (null-byte delimited — can't appear in user-authored text).
|
* (null-byte delimited — can't appear in user-authored text).
|
||||||
* Pass 2: replace each sentinel with the Pass 1 output for the referenced id.
|
* Pass 2: replace each sentinel with the Pass 1 output for the referenced id.
|
||||||
* Since Pass 1 output contains only sentinels (not live {id:description}
|
* Any sentinels that survive after that substitution are cycles — they
|
||||||
* tokens), this is one substitution deep. Any remaining sentinels after
|
* are resolved as "Label (symbol)" (the {id} expansion) rather than
|
||||||
* Pass 2 (self-references, unresolvable cycles) are stripped to empty.
|
* leaving an empty slot.
|
||||||
*
|
*
|
||||||
* Result for a mutual reference (id0 ↔ id2):
|
* Result for a mutual reference (pound ↔ dickload):
|
||||||
* - id0's description contains id2's Pass-1 text (with id2's back-reference stripped)
|
* pound's description: "See dickload (dl)"
|
||||||
* - id2's description contains id0's Pass-1 text (with id0's back-reference stripped)
|
* dickload's description: "See pound (lb)"
|
||||||
* One level of expansion, then stops cleanly.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Null-byte delimiters can't appear in user-authored strings.
|
// Null-byte delimiters can't appear in user-authored strings.
|
||||||
@@ -94,15 +93,21 @@ export function resolveAllDescriptions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pass 2: replace sentinels with Pass 1 output of the referenced id.
|
// Pass 2: replace sentinels with Pass 1 output of the referenced id.
|
||||||
// Strip any remaining sentinels (self-refs, unresolvable cycles) → empty string.
|
// Any sentinels surviving after that substitution are cycles — resolve them
|
||||||
|
// as Label (symbol) instead of leaving an empty slot.
|
||||||
const result = new Map<string, string>();
|
const result = new Map<string, string>();
|
||||||
for (const [id, p1] of pass1) {
|
for (const [id, p1] of pass1) {
|
||||||
result.set(
|
result.set(
|
||||||
id,
|
id,
|
||||||
p1
|
p1
|
||||||
.replace(SENTINEL_RE, (_match, refId: string) => pass1.get(refId) ?? '')
|
.replace(SENTINEL_RE, (_match, refId: string) => pass1.get(refId) ?? '')
|
||||||
// Strip any sentinels that survived (self-references or nested cycles)
|
.replace(SENTINEL_RE, (_match, refId: string) => {
|
||||||
.replace(SENTINEL_RE, '')
|
const u = unitMap.get(refId);
|
||||||
|
if (u) return `${u.label} (${u.symbol})`;
|
||||||
|
const g = groupMap.get(refId);
|
||||||
|
if (g) return g.label;
|
||||||
|
return '';
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,5 +132,11 @@ export function resolveDescription(
|
|||||||
const unit = unitMap.get(refId);
|
const unit = unitMap.get(refId);
|
||||||
return unit?.description ? resolveFields(unit.description, unitMap, groupMap) : '';
|
return unit?.description ? resolveFields(unit.description, unitMap, groupMap) : '';
|
||||||
})
|
})
|
||||||
.replace(SENTINEL_RE, ''); // strip surviving sentinels
|
.replace(SENTINEL_RE, (_match, refId: string) => {
|
||||||
|
const u = unitMap.get(refId);
|
||||||
|
if (u) return `${u.label} (${u.symbol})`;
|
||||||
|
const g = groupMap.get(refId);
|
||||||
|
if (g) return g.label;
|
||||||
|
return '';
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user