Files
hbm-foundry-system/scripts/parsers/helpers.ts
2026-06-09 22:06:56 +02:00

82 lines
2.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Polish-aware slug helper. Lowercases, strips diacritics, replaces
* whitespace and punctuation with hyphens, collapses repeats.
*/
export function slugify(input: string): string {
return input
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.replace(/ł/g, 'l')
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.replace(/-{2,}/g, '-');
}
/** Strip Polish diacritics for case-insensitive map lookups. */
export function normalizeKey(input: string): string {
return input
.toLowerCase()
.trim()
.replace(/\s+/g, ' ')
.normalize('NFC');
}
/** Parse "5:2" -> { threshold: 5, successes: 2 }. */
export function parseDifficulty(s: string): { threshold: number; successes: number } | null {
const m = s.trim().match(/^(\d+)\s*:\s*([\d\w]+)$/);
if (!m) return null;
const successes = isNaN(Number(m[2])) ? 1 : Number(m[2]);
return { threshold: Number(m[1]), successes };
}
/** Parse "1 punkt", "3 punkty", "5 punktów" → 1/3/5. Returns 0 on failure. */
export function parsePoints(s: string): number {
const m = s.trim().match(/^(\d+)/);
return m ? Number(m[1]) : 0;
}
/** Parse a comma- or whitespace-separated symbol list. */
export function parseList(s: string): string[] {
return s
.split(/[,;]+/)
.map((x) => x.trim())
.filter((x) => x.length > 0);
}
/**
* Parse a Polish range string into structure.
* "Na siebie" → { kind: 'self' }
* "Dotyk" → { kind: 'touch' }
* "15 m" → { kind: 'distance', value: 15, unit: 'm' }
* anything else → { kind: 'special', text }
*/
export function parseRange(s: string): { kind: string; value?: number; unit?: string; text?: string } {
const t = s.trim();
if (/^na siebie$/i.test(t)) return { kind: 'self' };
if (/^dotyk$/i.test(t)) return { kind: 'touch' };
const m = t.match(/^(\d+)\s*(m|km|cm)\b/i);
if (m) return { kind: 'distance', value: Number(m[1]), unit: m[2].toLowerCase() };
return { kind: 'special', text: t };
}
/**
* Parse area-of-effect text into structured shape.
* "3×8 m" → rectangle 3×8
* "promień 5 m" → sphere radius 5
* "stożek 10 m" → cone length 10
* "linia 20 m" → line length 20
*/
export function parseAreaOfEffect(s: string): { shape: string; x?: number; y?: number; unit?: string; text?: string } | null {
const t = s.trim();
let m = t.match(/(\d+)\s*[x×]\s*(\d+)\s*(m|km|cm)?/i);
if (m) return { shape: 'rectangle', x: Number(m[1]), y: Number(m[2]), unit: (m[3] ?? 'm').toLowerCase() };
m = t.match(/promień\s+(\d+)\s*(m|km|cm)?/i);
if (m) return { shape: 'sphere', x: Number(m[1]), unit: (m[2] ?? 'm').toLowerCase() };
m = t.match(/stożek\s+(\d+)\s*(m|km|cm)?/i);
if (m) return { shape: 'cone', x: Number(m[1]), unit: (m[2] ?? 'm').toLowerCase() };
m = t.match(/linia\s+(\d+)\s*(m|km|cm)?/i);
if (m) return { shape: 'line', x: Number(m[1]), unit: (m[2] ?? 'm').toLowerCase() };
return null;
}