wren/lost-property Public Public: anyone can read this; nobody can change it.
workbenchthis machine
Files fe26fca1242e118d0a6a72d88af55fc09071adcf
| 1 | /** |
| 2 | * The curatorial rules: pure functions, no I/O, no randomness. Everything a |
| 3 | * plaque says about an object — its catalogue number, its vitrine, its |
| 4 | * condition — is derived only from the object's id and the description its |
| 5 | * loser gave, so the same item always reads the same way. |
| 6 | */ |
| 7 | |
| 8 | export const VITRINES: readonly string[] = [ |
| 9 | "Outerwear and Umbrellas", |
| 10 | "Keys and Fastenings", |
| 11 | "Spectacles and Lenses", |
| 12 | "Small Electronics", |
| 13 | "Jewellery and Adornment", |
| 14 | "Papers and Correspondence", |
| 15 | "Children's Effects", |
| 16 | "Miscellanea", |
| 17 | ]; |
| 18 | |
| 19 | // Checked in order; the first match wins. Anything that matches nothing |
| 20 | // goes to Miscellanea, the last vitrine. |
| 21 | const KEYWORDS: readonly [RegExp, number][] = [ |
| 22 | [/\b(umbrellas?|coats?|jackets?|gloves?|scarves?|scarfs?|hats?|mittens?)\b/i, 0], |
| 23 | [/\b(keys?|padlocks?|keyrings?|locks?)\b/i, 1], |
| 24 | [/\b(glasses|spectacles|sunglasses|lenses?)\b/i, 2], |
| 25 | [/\b(phones?|chargers?|laptops?|tablets?|earbuds?|headphones?|cameras?|cables?|airpods?)\b/i, 3], |
| 26 | [/\b(rings?|necklaces?|bracelets?|earrings?|watches?|brooches?)\b/i, 4], |
| 27 | [/\b(books?|letters?|notebooks?|diaries|diary|papers?|envelopes?|postcards?)\b/i, 5], |
| 28 | [/\b(toys?|teddy|teddies|dolls?|dummies|dummy|pacifiers?)\b/i, 6], |
| 29 | ]; |
| 30 | |
| 31 | export function vitrineOf(description: string): number { |
| 32 | for (const [pattern, index] of KEYWORDS) if (pattern.test(description)) return index; |
| 33 | return VITRINES.length - 1; |
| 34 | } |
| 35 | |
| 36 | const CONDITIONS: readonly string[] = [ |
| 37 | "Wear consistent with ordinary use.", |
| 38 | "Good condition; minor surface wear.", |
| 39 | "Handled; edges softened with use.", |
| 40 | "Condition at time of loss not recorded.", |
| 41 | "As described by the finder; not further examined.", |
| 42 | "Stable condition; no active deterioration noted.", |
| 43 | ]; |
| 44 | |
| 45 | export function conditionOf(id: number): string { |
| 46 | return CONDITIONS[id % CONDITIONS.length]!; |
| 47 | } |
| 48 | |
| 49 | // A museum accession number: LP, the year it entered the collection, and |
| 50 | // its sequence within the collection — not within that year, since this |
| 51 | // museum is smaller than that distinction is worth. |
| 52 | export function catalogueNumber(id: number, createdAt: string): string { |
| 53 | const year = createdAt.slice(0, 4); |
| 54 | return `LP ${year}.${String(id).padStart(4, "0")}`; |
| 55 | } |