diff --git a/.changeset/cool-seahorses-cross.md b/.changeset/cool-seahorses-cross.md new file mode 100644 index 000000000000..bdef5a70becf --- /dev/null +++ b/.changeset/cool-seahorses-cross.md @@ -0,0 +1,5 @@ +--- +'create-svelte': patch +--- + +Use `satisfies` operator diff --git a/packages/create-svelte/templates/default/src/routes/sverdle/+page.server.ts b/packages/create-svelte/templates/default/src/routes/sverdle/+page.server.ts index 9e8075993ab6..58f3ad2a4cf1 100644 --- a/packages/create-svelte/templates/default/src/routes/sverdle/+page.server.ts +++ b/packages/create-svelte/templates/default/src/routes/sverdle/+page.server.ts @@ -1,9 +1,9 @@ import { invalid } from '@sveltejs/kit'; -import { Game } from './game'; +import { words, allowed } from './words.server'; import type { PageServerLoad, Actions } from './$types'; /** @type {import('./$types').PageServerLoad} */ -export const load: PageServerLoad = ({ cookies }) => { +export const load = (({ cookies }) => { const game = new Game(cookies.get('sverdle')); return { @@ -23,10 +23,10 @@ export const load: PageServerLoad = ({ cookies }) => { */ answer: game.answers.length >= 6 ? game.answer : null }; -}; +}) satisfies PageServerLoad; /** @type {import('./$types').Actions} */ -export const actions: Actions = { +export const actions = { /** * Modify game state in reaction to a keypress. If client-side JavaScript * is available, this will happen in the browser instead of here @@ -68,4 +68,80 @@ export const actions: Actions = { restart: async ({ cookies }) => { cookies.delete('sverdle'); } -}; +} satisfies Actions; + +class Game { + index: number; + guesses: string[]; + answers: string[]; + answer: string; + + /** + * Create a game object from the player's cookie, or initialise a new game + * @param {string | undefined} serialized + */ + constructor(serialized: string | undefined) { + if (serialized) { + const [index, guesses, answers] = serialized.split('-'); + + this.index = +index; + this.guesses = guesses ? guesses.split(' ') : []; + this.answers = answers ? answers.split(' ') : []; + } else { + this.index = Math.floor(Math.random() * words.length); + this.guesses = ['', '', '', '', '', '']; + this.answers = /** @type {string[]} */ [] /***/; + } + + this.answer = words[this.index]; + } + + /** + * Update game state based on a guess of a five-letter word. Returns + * true if the guess was valid, false otherwise + * @param {string[]} letters + */ + enter(letters: string[]) { + const word = letters.join(''); + const valid = allowed.has(word); + + if (!valid) return false; + + this.guesses[this.answers.length] = word; + + const available = Array.from(this.answer); + const answer = Array(5).fill('_'); + + // first, find exact matches + for (let i = 0; i < 5; i += 1) { + if (letters[i] === available[i]) { + answer[i] = 'x'; + available[i] = ' '; + } + } + + // then find close matches (this has to happen + // in a second step, otherwise an early close + // match can prevent a later exact match) + for (let i = 0; i < 5; i += 1) { + if (answer[i] === '_') { + const index = available.indexOf(letters[i]); + if (index !== -1) { + answer[i] = 'c'; + available[index] = ' '; + } + } + } + + this.answers.push(answer.join('')); + + return true; + } + + /** + * Serialize game state so it can be set as a cookie + */ + toString() { + return `${this.index}-${this.guesses.join(' ')}-${this.answers.join(' ')}`; + } +} diff --git a/packages/kit/src/core/sync/write_types/index.spec.js b/packages/kit/src/core/sync/write_types/index.spec.js index 41f696fc6e47..390019dabbf1 100644 --- a/packages/kit/src/core/sync/write_types/index.spec.js +++ b/packages/kit/src/core/sync/write_types/index.spec.js @@ -265,4 +265,26 @@ test('Rewrites action types for a TypeScript module', () => { ); }); +test('Leaves satisfies operator untouched', () => { + const source = ` + import type { Actions, PageServerLoad, RequestEvent } from './$types'; + export function load({ params }) { + return { + a: 1 + }; + } satisfies PageServerLoad + export const actions = { + a: () => {}, + b: (param: RequestEvent) => {}, + c: (param) => {}, + } satisfies Actions + `; + + const rewritten = tweak_types(source, true); + + assert.equal(rewritten?.exports, ['load', 'actions']); + assert.equal(rewritten?.modified, false); + assert.equal(rewritten?.code, source); +}); + test.run();