Fursona schema validation

This commit is contained in:
Gabriel Simmer 2023-05-05 22:14:42 +01:00
parent 53990370ab
commit bb1e4e5377
Signed by: arch
GPG key ID: C81B106D46C5B875
2 changed files with 94 additions and 20 deletions

View file

@ -38,3 +38,48 @@ export interface Sona {
birthdate?: string;
colors?: string[];
}
// Validate fursona
export function validateFursona(fursona: Sona): string[] {
let reasons = [];
if (!fursona.name) reasons.push('Missing fursona name');
if (!fursona.species) reasons.push('Missing fursona species');
if (!fursona.description) reasons.push('Missing fursona description');
if (fursona.description.length > 250) reasons.push('Fursona description is too long');
if (fursona.ref && !isURL(fursona.ref)) reasons.push('Fursona ref is not a valid URL');
if (fursona.avatar && !isURL(fursona.avatar)) reasons.push('Fursona avatar is not a valid URL');
if (fursona.age && fursona.age < 0) reasons.push('Fursona age is negative');
if (fursona.birthdate && !isISO8601(fursona.birthdate))
reasons.push('Fursona birthdate is not a valid ISO 8601 date');
if (fursona.colors && !Array.isArray(fursona.colors))
reasons.push('Fursona colors is not an array');
if (fursona.colors && fursona.colors.some((color) => !isColor(color)))
reasons.push('Fursona colors contains an invalid color');
return reasons;
}
// Validate fursona schema
export function validateFursonaSchema(fursonaSchema: FursonaSchema): boolean {
if (!fursonaSchema.sonas) return false;
if (!Array.isArray(fursonaSchema.sonas)) return false;
if (fursonaSchema.sonas.length > 10) return false;
if (fursonaSchema.sonas.some((sona) => !validateFursona(sona))) return false;
return true;
}
function isColor(color: string): boolean {
return /^#([0-9a-f]{3}){1,2}$/i.test(color);
}
function isURL(url: string): boolean {
try {
new URL(url);
return true;
} catch (err) {
return false;
}
}
function isISO8601(date: string): boolean {
return !isNaN(Date.parse(date));
}

View file

@ -1,39 +1,67 @@
<script lang="ts">
import { onMount } from 'svelte';
import type { FursonaSchema, Sona } from '$lib/Fursona';
import { validateFursona } from '$lib/Fursona';
export let fursona = {} as Sona;
const validation = validateFursona(fursona);
// Parse birthdate
if (fursona.birthdate) {
fursona.birthdate = new Date(fursona.birthdate);
}
function toggleReasons() {
const reasons = document.getElementById('reasons');
if (reasons.classList.contains('hidden')) {
reasons.classList.remove('hidden');
} else {
reasons.classList.add('hidden');
}
}
</script>
<div
class="flex flex-col items-center justify-center text-slate-900 dark:text-white dark:bg-slate-500"
>
{#if fursona.avatar}
<img src={fursona.avatar} alt="{fursona.name} avatar image" class="rounded" />
>
{#if validation.length > 0}
<div
class="flex flex-col items-center justify-center text-slate-900 dark:text-white dark:bg-slate-500"
>
<button class="text-center" on:click={toggleReasons}>
⚠️: Fursona data does not comply to schema
</button>
<div class="hidden" id="reasons">
{#each validation as error}
<ul class="list-inside text-center">
<li>{error}</li>
</ul>
{/each}
</div>
</div>
{/if}
<h1 class="text-3xl leading-none md:text-3xl lg:text-3xl">
{fursona.name}
{#if fursona.pronouns}
({fursona.pronouns})
{/if}
{#if fursona.avatar}
<img src={fursona.avatar} alt="{fursona.name} avatar image" class="rounded" />
{/if}
<h1 class="text-3xl text-center leading-none md:text-3xl lg:text-3xl">
{fursona.name}
{#if fursona.pronouns}
({fursona.pronouns})
{/if}
</h1>
<h2 class="mb-2 text-2xl leading-none md:text-2xl lg:text-2xl">
{#if fursona.gender}
{fursona.gender}
{/if}
{fursona.species}
{#if fursona.gender}
{fursona.gender}
{/if}
{fursona.species}
</h2>
<p class="mb-3 text-center">{fursona.description}</p>
{#if fursona.birthdate && fursona.age}
<p class="mb-3 text-center">🎂{fursona.birthdate.toLocaleDateString()} ({fursona.age})</p>
<p class="mb-3 text-center">🎂{fursona.birthdate.toLocaleDateString()} ({fursona.age})</p>
{:else if fursona.birthdate}
<p class="mb-3 text-center">🎂{fursona.birthdate.toLocaleDateString()}</p>
<p class="mb-3 text-center">🎂{fursona.birthdate.toLocaleDateString()}</p>
{:else if fursona.age}
<p class="mb-3 text-center">{fursona.age}</p>
<p class="mb-3 text-center">{fursona.age}</p>
{/if}
<div class="grid grid-cols-3 md:grid-cols-4 lg:grid-cols-4">
{#each fursona.colors as color}
@ -42,12 +70,13 @@
<p class="text-sm font-mono">{color}</p>
</div>
{/each}
</div>
</div>
{#if fursona.ref}
<a
href={fursona.ref}
target="_blank"
class="mb-4 mt-4 text-md text-blue-500 dark:text-blue-200 underline">View Ref Sheet</a>
<a
href={fursona.ref}
target="_blank"
class="mb-4 mt-4 text-md text-blue-500 dark:text-blue-200 underline">View Ref Sheet</a
>
{/if}
</div>