feat: dynamic field labels, optionally overriding field names per species
This commit is contained in:
parent
a0060ca4bb
commit
a2b904811a
21 changed files with 322 additions and 73 deletions
32
src/lib/data/parse.test.ts
Normal file
32
src/lib/data/parse.test.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { parseSpecies } from './parse';
|
||||
|
||||
describe('parseSpecies', () => {
|
||||
it('parses labels section into a record', () => {
|
||||
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<species id="tajara" name="Tajara">
|
||||
<labels>
|
||||
<label for="subspecies">Ethnicity</label>
|
||||
<label for="skin-color">Fur Colour</label>
|
||||
</labels>
|
||||
<subspecies>
|
||||
<entry id="hharar" name="Hharar">
|
||||
<description>The typical Tajara.</description>
|
||||
</entry>
|
||||
</subspecies>
|
||||
</species>`;
|
||||
const result = parseSpecies(xml);
|
||||
expect(result.labels).toEqual({
|
||||
subspecies: 'Ethnicity',
|
||||
'skin-color': 'Fur Colour'
|
||||
});
|
||||
});
|
||||
|
||||
it('returns empty labels when no labels section exists', () => {
|
||||
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<species id="unathi" name="Unathi">
|
||||
</species>`;
|
||||
const result = parseSpecies(xml);
|
||||
expect(result.labels).toEqual({});
|
||||
});
|
||||
});
|
||||
|
|
@ -5,7 +5,7 @@ import type { Template, RecordDef, FieldDef, SelectOption } from '../types';
|
|||
const parser = new XMLParser({
|
||||
ignoreAttributes: false,
|
||||
attributeNamePrefix: '@_',
|
||||
isArray: (name) => ['entry', 'ref', 'field', 'record', 'option', 'citizenship', 'language'].includes(name),
|
||||
isArray: (name) => ['entry', 'ref', 'field', 'record', 'option', 'citizenship', 'language', 'label'].includes(name),
|
||||
trimValues: true
|
||||
});
|
||||
|
||||
|
|
@ -14,6 +14,15 @@ function extractRefs(container: any): string[] {
|
|||
return container.ref.map((r: any) => r['@_id']);
|
||||
}
|
||||
|
||||
function extractLabels(container: any): Record<string, string> {
|
||||
if (!container?.label) return {};
|
||||
const labels: Record<string, string> = {};
|
||||
for (const l of container.label) {
|
||||
labels[l['@_for']] = typeof l === 'string' ? l : l['#text'];
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
|
||||
export function parseSpecies(xml: string): SpeciesData {
|
||||
const root = parser.parse(xml).species;
|
||||
const subspecies = root.subspecies?.entry ?? [];
|
||||
|
|
@ -22,7 +31,7 @@ export function parseSpecies(xml: string): SpeciesData {
|
|||
id: root['@_id'],
|
||||
name: root['@_name'],
|
||||
description: root.description?.trim(),
|
||||
subspeciesLabel: root['@_subspeciesLabel'],
|
||||
labels: extractLabels(root.labels),
|
||||
languages: extractRefs(root.languages),
|
||||
citizenships: extractRefs(root.citizenships),
|
||||
subspecies: subspecies.map((e: any) => ({
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ export interface SpeciesData {
|
|||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
subspeciesLabel: string;
|
||||
labels: Record<string, string>;
|
||||
subspecies: { id: string; name: string; description?: string }[];
|
||||
languages: string[];
|
||||
citizenships: string[];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue