feat(data): parser for data files
This commit is contained in:
parent
95b307d6bb
commit
8ad0041d23
3 changed files with 154 additions and 0 deletions
13
src/lib/data/index.ts
Normal file
13
src/lib/data/index.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { parseSpecies, parseCitizenships, parseLanguages } from './parse';
|
||||||
|
import citizenshipsXml from '../../../data/citizenships.xml?raw';
|
||||||
|
import languagesXml from '../../../data/languages.xml?raw';
|
||||||
|
|
||||||
|
const speciesModules = import.meta.glob('../../../data/species/*.xml', {
|
||||||
|
query: '?raw',
|
||||||
|
import: 'default',
|
||||||
|
eager: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const species = Object.values(speciesModules).map((xml) => parseSpecies(xml as string));
|
||||||
|
export const citizenships = parseCitizenships(citizenshipsXml);
|
||||||
|
export const languages = parseLanguages(languagesXml);
|
||||||
120
src/lib/data/parse.ts
Normal file
120
src/lib/data/parse.ts
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
import { XMLParser } from 'fast-xml-parser';
|
||||||
|
import type { SpeciesData, CitizenshipData, LanguageData } from './types';
|
||||||
|
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),
|
||||||
|
trimValues: true
|
||||||
|
});
|
||||||
|
|
||||||
|
function extractRefs(container: any): string[] {
|
||||||
|
if (!container?.ref) return [];
|
||||||
|
return container.ref.map((r: any) => r['@_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseSpecies(xml: string): SpeciesData {
|
||||||
|
const root = parser.parse(xml).species;
|
||||||
|
const subspecies = root.subspecies?.entry ?? [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: root['@_id'],
|
||||||
|
name: root['@_name'],
|
||||||
|
description: root.description.trim(),
|
||||||
|
subspeciesLabel: root['@_subspeciesLabel'],
|
||||||
|
languages: extractRefs(root.languages),
|
||||||
|
citizenships: extractRefs(root.citizenships),
|
||||||
|
subspecies: subspecies.map((e: any) => ({
|
||||||
|
id: e['@_id'],
|
||||||
|
name: e['@_name'],
|
||||||
|
description: e.description.trim()
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseCitizenships(xml: string): CitizenshipData[] {
|
||||||
|
const root = parser.parse(xml).citizenships;
|
||||||
|
return root.citizenship.map((c: any) => ({
|
||||||
|
id: c['@_id'],
|
||||||
|
name: c['@_name'],
|
||||||
|
description: c.description?.trim()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseLanguages(xml: string): LanguageData[] {
|
||||||
|
const root = parser.parse(xml).languages;
|
||||||
|
return root.language.map((l: any) => ({
|
||||||
|
id: l['@_id'],
|
||||||
|
name: l['@_name'],
|
||||||
|
description: l.description.trim()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function slugify(label: string): string {
|
||||||
|
return label.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseOptions(field: any): SelectOption[] {
|
||||||
|
if (!field.option) return [];
|
||||||
|
return field.option.map((o: any) => ({
|
||||||
|
value: o['@_value'],
|
||||||
|
label: o['@_label']
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseField(raw: any): FieldDef {
|
||||||
|
const base = {
|
||||||
|
key: slugify(raw['@_label']),
|
||||||
|
label: raw['@_label']
|
||||||
|
};
|
||||||
|
const type = raw['@_type'];
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'text':
|
||||||
|
case 'textarea':
|
||||||
|
case 'date':
|
||||||
|
return { ...base, type, placeholder: raw['@_placeholder'] };
|
||||||
|
case 'list':
|
||||||
|
case 'height':
|
||||||
|
case 'weight':
|
||||||
|
case 'species':
|
||||||
|
case 'subspecies':
|
||||||
|
case 'citizenship':
|
||||||
|
case 'languages':
|
||||||
|
return { ...base, type };
|
||||||
|
case 'number':
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
type,
|
||||||
|
min: raw['@_min'] != null ? Number(raw['@_min']) : undefined,
|
||||||
|
max: raw['@_max'] != null ? Number(raw['@_max']) : undefined,
|
||||||
|
unit: raw['@_unit']
|
||||||
|
};
|
||||||
|
case 'select':
|
||||||
|
case 'multi-select':
|
||||||
|
case 'checkbox':
|
||||||
|
return { ...base, type, options: parseOptions(raw) };
|
||||||
|
default:
|
||||||
|
return { ...base, type: 'text' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseTemplate(xml: string, id: string): Template {
|
||||||
|
const root = parser.parse(xml).template;
|
||||||
|
|
||||||
|
const records: RecordDef[] = root.record.map((r: any) => ({
|
||||||
|
type: r['@_type'],
|
||||||
|
expanded: r['@_expanded'] === 'true',
|
||||||
|
preamble: r.preamble?.trim(),
|
||||||
|
fields: r.field.map(parseField)
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name: root['@_name'],
|
||||||
|
description: root.description ?? '',
|
||||||
|
schemaVersion: Number(root['@_schemaVersion'] ?? 1),
|
||||||
|
records
|
||||||
|
};
|
||||||
|
}
|
||||||
21
src/lib/data/types.ts
Normal file
21
src/lib/data/types.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
export interface SpeciesData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
subspeciesLabel: string;
|
||||||
|
subspecies: { id: string; name: string; description: string }[];
|
||||||
|
languages: string[];
|
||||||
|
citizenships: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CitizenshipData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LanguageData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue