mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
invention purchase, at least, how I think they should work
This commit is contained in:
@@ -37,6 +37,25 @@ export const MAX_CLUB_DESCRIPTION_LENGTH = 512
|
||||
export const MAX_EVENT_NAME_LENGTH = 64
|
||||
export const MAX_EVENT_DESCRIPTION_LENGTH = 512
|
||||
|
||||
/**
|
||||
* Invention limits. A name is a title a player types into the invention-save box and
|
||||
* reads back in a browse tile, so it allows the punctuation a title needs — but
|
||||
* nothing else, since it is also what invention search matches on. The minimum is real:
|
||||
* one- and two-character names are unsearchable and unreadable in a tile, and the client
|
||||
* offers `Untitled` rather than an empty box.
|
||||
*/
|
||||
export const MIN_INVENTION_NAME_LENGTH = 3
|
||||
export const MAX_INVENTION_NAME_LENGTH = 24
|
||||
export const MAX_INVENTION_DESCRIPTION_LENGTH = 512
|
||||
|
||||
/**
|
||||
* One invention tag. Short and letters-only because tags are a controlled vocabulary the
|
||||
* browse chips are derived from (see `getInventionTagFilters`) — a tag with digits,
|
||||
* punctuation or spaces makes a chip nobody else will ever type again. Tags are stored
|
||||
* lowercased, so the rule is checked against the normalized form, not what was typed.
|
||||
*/
|
||||
export const MAX_INVENTION_TAG_LENGTH = 15
|
||||
|
||||
/**
|
||||
* Length in code points rather than UTF-16 units, so an emoji or other astral character
|
||||
* counts once instead of twice — the way a player counts what they typed.
|
||||
@@ -74,6 +93,69 @@ export function nameRejection(value: string, label: string, max: number): string
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Letters, digits, spaces, dashes and colons — the title charset. Wider than
|
||||
* `NAME_PATTERN` because an invention is a thing with a name ("Grappling Hook v2",
|
||||
* "Speed-Boost Pad"), not an identifier someone types into a sign-in box. Still no
|
||||
* arbitrary Unicode, for the same homoglyph reasons.
|
||||
*
|
||||
* The colon is not decorative: an invention the player never named is called after the
|
||||
* moment it was saved (`071126 13:10:50`), generated by the CLIENT, so a rule without it
|
||||
* would refuse every unnamed save the game makes. The dash stays last in the class so it
|
||||
* reads as a literal rather than a range.
|
||||
*/
|
||||
const INVENTION_NAME_PATTERN = /^[A-Za-z0-9 :-]+$/
|
||||
|
||||
/** Lowercase letters only — the normalized form a tag is stored in. */
|
||||
const INVENTION_TAG_PATTERN = /^[a-z]+$/
|
||||
|
||||
/**
|
||||
* Why a player-supplied invention name is unacceptable, or `null` when it's fine.
|
||||
*
|
||||
* Callers pass the TRIMMED name: leading and trailing spaces are the player's typing,
|
||||
* not part of what they named the thing, and counting them toward the minimum would let
|
||||
* `" a "` through.
|
||||
*/
|
||||
export function inventionNameRejection(value: string): string | null {
|
||||
if (glyphLength(value) < MIN_INVENTION_NAME_LENGTH) {
|
||||
return `Invention names must be at least ${MIN_INVENTION_NAME_LENGTH} characters.`
|
||||
}
|
||||
if (glyphLength(value) > MAX_INVENTION_NAME_LENGTH) {
|
||||
return `Invention names can be at most ${MAX_INVENTION_NAME_LENGTH} characters.`
|
||||
}
|
||||
if (!INVENTION_NAME_PATTERN.test(value)) {
|
||||
return 'Invention names can only contain letters, numbers, spaces, dashes and colons.'
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Why an invention description is unacceptable, or `null` when it's fine. Length only —
|
||||
* a description is prose, so nothing is refused for the characters it's made of, and an
|
||||
* empty one is fine (it's how a creator clears the field).
|
||||
*/
|
||||
export function inventionDescriptionRejection(value: string): string | null {
|
||||
if (glyphLength(value) > MAX_INVENTION_DESCRIPTION_LENGTH) {
|
||||
return `Invention descriptions can be at most ${MAX_INVENTION_DESCRIPTION_LENGTH} characters.`
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Why an invention tag is unacceptable, or `null` when it's fine. Pass the NORMALIZED
|
||||
* tag (trimmed and lowercased, as `setInventionTags` stores it) — checking what was typed
|
||||
* instead would refuse `Racing` for a capital that never reaches the database.
|
||||
*/
|
||||
export function inventionTagRejection(value: string): string | null {
|
||||
if (value.length > MAX_INVENTION_TAG_LENGTH) {
|
||||
return `Invention tags can be at most ${MAX_INVENTION_TAG_LENGTH} characters.`
|
||||
}
|
||||
if (!INVENTION_TAG_PATTERN.test(value)) {
|
||||
return 'Invention tags can only contain letters.'
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a supplied email is one worth storing — RFC 5321/5322 syntax, via `isemail`.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user