From d8e382712c603e421a459167bdea890ddc73f1f4 Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Wed, 8 Nov 2023 05:34:37 -0800 Subject: [PATCH] site: fix type errors in JS files (#9354) --- sites/svelte.dev/src/lib/db/client.js | 8 ++- sites/svelte.dev/src/lib/db/gist.js | 12 +++-- sites/svelte.dev/src/lib/db/session.js | 6 +-- sites/svelte.dev/src/lib/server/docs/index.js | 12 +++-- .../src/lib/server/examples/index.js | 14 ++++- .../src/lib/server/examples/types.d.ts | 6 ++- .../src/lib/server/tutorial/index.js | 13 ++++- .../src/lib/server/tutorial/types.d.ts | 16 ++++-- sites/svelte.dev/src/lib/time.js | 50 +++++++++--------- sites/svelte.dev/src/lib/utils/events.js | 6 +++ sites/svelte.dev/src/lib/utils/examples.js | 10 ++++ .../src/routes/(authed)/apps/+page.server.js | 3 +- .../src/routes/(authed)/repl/+page.js | 11 ++-- .../(authed)/repl/[id]/AppControls.svelte | 2 +- .../routes/(authed)/repl/[id]/downloadBlob.js | 4 ++ .../(authed)/repl/api/[id].json/+server.js | 5 +- .../src/routes/auth/callback/+server.js | 15 +++--- .../src/routes/auth/login/+server.js | 2 +- .../src/routes/blog/rss.xml/+server.js | 3 ++ .../src/routes/content.json/content.server.js | 51 +++++++++++-------- 20 files changed, 164 insertions(+), 85 deletions(-) diff --git a/sites/svelte.dev/src/lib/db/client.js b/sites/svelte.dev/src/lib/db/client.js index b5a5437781e1..86143c79cffa 100644 --- a/sites/svelte.dev/src/lib/db/client.js +++ b/sites/svelte.dev/src/lib/db/client.js @@ -2,8 +2,14 @@ import { dev } from '$app/environment'; import { SUPABASE_URL, SUPABASE_KEY } from '$env/static/private'; import { createClient } from '@supabase/supabase-js'; +const client_enabled = !!(!dev || (SUPABASE_URL && SUPABASE_KEY)); + +/** + * @type {import('@supabase/supabase-js').SupabaseClient} + */ +// @ts-ignore-line export const client = - (!dev || (SUPABASE_URL && SUPABASE_KEY)) && + client_enabled && createClient(SUPABASE_URL, SUPABASE_KEY, { global: { fetch }, auth: { persistSession: false } diff --git a/sites/svelte.dev/src/lib/db/gist.js b/sites/svelte.dev/src/lib/db/gist.js index f1c4d9f86233..5b60adeb6710 100644 --- a/sites/svelte.dev/src/lib/db/gist.js +++ b/sites/svelte.dev/src/lib/db/gist.js @@ -8,6 +8,10 @@ const PAGE_SIZE = 90; /** * @param {User} user + * @param {{ + * offset: number; + * search: string | null; + * }} opts */ export async function list(user, { offset, search }) { const { data, error } = await client.rpc('gist_list', { @@ -20,9 +24,11 @@ export async function list(user, { offset, search }) { if (error) throw new Error(error.message); // normalize IDs - data.forEach((gist) => { - gist.id = gist.id.replace(/-/g, ''); - }); + data.forEach( + /** @param {{id:string}} gist */ (gist) => { + gist.id = gist.id.replace(/-/g, ''); + } + ); return { gists: data.slice(0, PAGE_SIZE), diff --git a/sites/svelte.dev/src/lib/db/session.js b/sites/svelte.dev/src/lib/db/session.js index 49872cbfda87..a54068bf538b 100644 --- a/sites/svelte.dev/src/lib/db/session.js +++ b/sites/svelte.dev/src/lib/db/session.js @@ -5,7 +5,7 @@ import { client } from './client.js'; /** @typedef {import('./types').User} User */ /** - * @type {import('flru').flruCache} + * @type {import('flru').flruCache} */ const session_cache = flru(1000); @@ -39,7 +39,7 @@ export async function create(user) { /** * @param {string} sessionid - * @returns {Promise} + * @returns {Promise} */ export async function read(sessionid) { if (!sessionid) return null; @@ -58,7 +58,7 @@ export async function read(sessionid) { ); } - return session_cache.get(sessionid); + return session_cache.get(sessionid) || null; } /** @param {string} sessionid */ diff --git a/sites/svelte.dev/src/lib/server/docs/index.js b/sites/svelte.dev/src/lib/server/docs/index.js index 8e5e591115d4..486662553c21 100644 --- a/sites/svelte.dev/src/lib/server/docs/index.js +++ b/sites/svelte.dev/src/lib/server/docs/index.js @@ -99,6 +99,7 @@ export function get_docs_list(docs_data) { })); } +/** @param {string} str */ const titled = async (str) => removeMarkdown( escape(await markedTransform(str, { paragraph: (txt) => txt })) @@ -111,7 +112,10 @@ const titled = async (str) => .replace(/<(\/)?(em|b|strong|code)>/g, '') ); -/** @param {string} markdown */ +/** + * @param {string} markdown + * @returns {Promise} + */ export async function get_sections(markdown) { const lines = markdown.split('\n'); const root = /** @type {import('./types').Section} */ ({ @@ -141,7 +145,9 @@ export async function get_sections(markdown) { }; // Add the new node to the tree - currentNodes[level].sections.push(newNode); + const sections = currentNodes[level].sections; + if (!sections) throw new Error(`Could not find section ${level}`); + sections.push(newNode); // Prepare for potential children of the new node currentNodes = currentNodes.slice(0, level + 1); @@ -152,5 +158,5 @@ export async function get_sections(markdown) { } } - return root.sections; + return /** @type {import('./types').Section[]} */ (root.sections); } diff --git a/sites/svelte.dev/src/lib/server/examples/index.js b/sites/svelte.dev/src/lib/server/examples/index.js index 0ca9347dfbef..759a72746e00 100644 --- a/sites/svelte.dev/src/lib/server/examples/index.js +++ b/sites/svelte.dev/src/lib/server/examples/index.js @@ -25,6 +25,7 @@ export async function get_examples_data(base = CONTENT_BASE_PATHS.EXAMPLES) { const examples = []; for (const subdir of await readdir(base)) { + /** @type {import('./types').ExamplesDatum} */ const section = { title: '', // Initialise with empty slug: subdir.split('-').slice(1).join('-'), @@ -51,13 +52,24 @@ export async function get_examples_data(base = CONTENT_BASE_PATHS.EXAMPLES) { await readFile(`${example_base_dir}/meta.json`, 'utf-8') ).title; + /** + * @type {Array<{ + * name: string; + * type: string; + * content: string; + * }>} + */ const files = []; for (const file of (await readdir(example_base_dir)).filter( (file) => !file.endsWith('meta.json') )) { + const type = file.split('.').at(-1); + if (!type) { + throw new Error(`Could not determine type from ${file}`); + } files.push({ name: file, - type: file.split('.').at(-1), + type, content: await readFile(`${example_base_dir}/${file}`, 'utf-8') }); } diff --git a/sites/svelte.dev/src/lib/server/examples/types.d.ts b/sites/svelte.dev/src/lib/server/examples/types.d.ts index 71abd66311e0..4be706354ddc 100644 --- a/sites/svelte.dev/src/lib/server/examples/types.d.ts +++ b/sites/svelte.dev/src/lib/server/examples/types.d.ts @@ -1,4 +1,4 @@ -export type ExamplesData = { +export interface ExamplesDatum { title: string; slug: string; examples: { @@ -10,7 +10,9 @@ export type ExamplesData = { name: string; }[]; }[]; -}[]; +} + +export type ExamplesData = ExamplesDatum[]; export interface Example { title: string; diff --git a/sites/svelte.dev/src/lib/server/tutorial/index.js b/sites/svelte.dev/src/lib/server/tutorial/index.js index 955a789e659b..2ba4f7ef4cf9 100644 --- a/sites/svelte.dev/src/lib/server/tutorial/index.js +++ b/sites/svelte.dev/src/lib/server/tutorial/index.js @@ -30,6 +30,7 @@ export async function get_tutorial_data(base = CONTENT_BASE_PATHS.TUTORIAL) { const tutorials = []; for (const subdir of await readdir(base)) { + /** @type {import('./types').TutorialDatum} */ const section = { title: '', // Initialise with empty slug: subdir.split('-').slice(1).join('-'), @@ -55,6 +56,12 @@ export async function get_tutorial_data(base = CONTENT_BASE_PATHS.TUTORIAL) { const { metadata, body } = extractFrontmatter(contents); // Get the contents of the apps. + /** + * @type {{ + * initial: import('./types').CompletionState[]; + * complete: import('./types').CompletionState[]; + * }} + */ const completion_states_data = { initial: [], complete: [] }; for (const app_dir of await readdir(tutorial_base_dir)) { if (!app_dir.startsWith('app-')) continue; @@ -63,9 +70,13 @@ export async function get_tutorial_data(base = CONTENT_BASE_PATHS.TUTORIAL) { const app_contents = await readdir(app_dir_path, 'utf-8'); for (const file of app_contents) { + const type = file.split('.').at(-1); + if (!type) { + throw new Error(`Could not determine type from ${file}`); + } completion_states_data[app_dir === 'app-a' ? 'initial' : 'complete'].push({ name: file, - type: file.split('.').at(-1), + type, content: await readFile(`${app_dir_path}/${file}`, 'utf-8') }); } diff --git a/sites/svelte.dev/src/lib/server/tutorial/types.d.ts b/sites/svelte.dev/src/lib/server/tutorial/types.d.ts index 2ec5bd99fb1c..4c787ee3ad2a 100644 --- a/sites/svelte.dev/src/lib/server/tutorial/types.d.ts +++ b/sites/svelte.dev/src/lib/server/tutorial/types.d.ts @@ -1,4 +1,4 @@ -export type TutorialData = { +export interface TutorialDatum { title: string; slug: string; tutorials: { @@ -6,10 +6,18 @@ export type TutorialData = { slug: string; dir: string; content: string; - initial: { name: string; type: string; content: string }[]; - complete: { name: string; type: string; content: string }[]; + initial: CompletionState[]; + complete: CompletionState[]; }[]; -}[]; +} + +export interface CompletionState { + name: string; + type: string; + content: string; +} + +export type TutorialData = TutorialDatum[]; export interface Tutorial { title: string; diff --git a/sites/svelte.dev/src/lib/time.js b/sites/svelte.dev/src/lib/time.js index 2380690aedff..53f4660ffddc 100644 --- a/sites/svelte.dev/src/lib/time.js +++ b/sites/svelte.dev/src/lib/time.js @@ -1,30 +1,28 @@ -// adapted from https://github.com/digplan/time-ago -// https://github.com/digplan/time-ago/blob/master/license.txt -const o = { - second: 1000, - minute: 60 * 1000, - hour: 60 * 1000 * 60, - day: 24 * 60 * 1000 * 60, - week: 7 * 24 * 60 * 1000 * 60, - month: 30 * 24 * 60 * 1000 * 60, - year: 365 * 24 * 60 * 1000 * 60 +const formatter = new Intl.RelativeTimeFormat(undefined, { + numeric: 'auto' +}); + +const DIVISIONS = { + seconds: 60, + minutes: 60, + hours: 24, + days: 7, + weeks: 4.34524, + months: 12, + years: Number.POSITIVE_INFINITY }; -export const ago = (nd, s) => { - var r = Math.round, - dir = ' ago', - pl = function (v, n) { - return s === undefined ? n + ' ' + v + (n > 1 ? 's' : '') + dir : n + v.substring(0, 1); - }, - ts = Date.now() - new Date(nd).getTime(), - ii; - if (ts < 0) { - ts *= -1; - dir = ' from now'; - } - for (var i in o) { - if (r(ts) < o[i]) return pl(ii || 'm', r(ts / (o[ii] || 1))); - ii = i; +/** + * @param {Date} date + */ +export const ago = (date) => { + let duration = (date.getTime() - new Date().getTime()) / 1000; + + for (const [name, amount] of Object.entries(DIVISIONS)) { + if (Math.abs(duration) < amount) { + const format = /** @type {keyof(DIVISIONS)} */ (name); + return formatter.format(Math.round(duration), format); + } + duration /= amount; } - return pl(i, r(ts / o[i])); }; diff --git a/sites/svelte.dev/src/lib/utils/events.js b/sites/svelte.dev/src/lib/utils/events.js index 5575812a9536..d407b2f3c713 100644 --- a/sites/svelte.dev/src/lib/utils/events.js +++ b/sites/svelte.dev/src/lib/utils/events.js @@ -1,7 +1,13 @@ +/** @param {number} code */ export function keyEvent(code) { + /** + * @param {HTMLInputElement} node + * @param {(event: KeyboardEvent) => void} callback + */ return function (node, callback) { node.addEventListener('keydown', handleKeydown); + /** @param {KeyboardEvent} event */ function handleKeydown(event) { if (event.keyCode === code) { callback.call(this, event); diff --git a/sites/svelte.dev/src/lib/utils/examples.js b/sites/svelte.dev/src/lib/utils/examples.js index e087d356efde..4eb97f6074df 100644 --- a/sites/svelte.dev/src/lib/utils/examples.js +++ b/sites/svelte.dev/src/lib/utils/examples.js @@ -1,3 +1,11 @@ +/** + * @param {Array<{ + * content: string; + * name: string; + * source: string; + * type: string; + * }>} files + */ export function process_example(files) { return files .map((file) => { @@ -12,5 +20,7 @@ export function process_example(files) { if (a.type === 'svelte') return -1; if (b.type === 'svelte') return 1; + + return 0; }); } diff --git a/sites/svelte.dev/src/routes/(authed)/apps/+page.server.js b/sites/svelte.dev/src/routes/(authed)/apps/+page.server.js index ffe4739a333c..a85cb5796b1f 100644 --- a/sites/svelte.dev/src/routes/(authed)/apps/+page.server.js +++ b/sites/svelte.dev/src/routes/(authed)/apps/+page.server.js @@ -9,7 +9,8 @@ export async function load({ url, parent }) { const { user } = await parent(); if (user) { - const offset = url.searchParams.get('offset') ? parseInt(url.searchParams.get('offset')) : 0; + const offset_param = url.searchParams.get('offset'); + const offset = offset_param ? parseInt(offset_param) : 0; const search = url.searchParams.get('search'); ({ gists, next } = await gist.list(user, { offset, search })); diff --git a/sites/svelte.dev/src/routes/(authed)/repl/+page.js b/sites/svelte.dev/src/routes/(authed)/repl/+page.js index 12eff1cdd3df..36c04f0fd084 100644 --- a/sites/svelte.dev/src/routes/(authed)/repl/+page.js +++ b/sites/svelte.dev/src/routes/(authed)/repl/+page.js @@ -8,17 +8,14 @@ export function load({ url }) { const vim = query.get('vim'); // redirect to v2 REPL if appropriate - if (/^[^>]?[12]/.test(version)) { + if (version && /^[^>]?[12]/.test(version)) { throw redirect(302, `https://v2.svelte.dev/repl?${query}`); } const id = gist || example || 'hello-world'; // we need to filter out null values - const q = new URLSearchParams( - Object.entries({ - version, - vim - }).filter(([, value]) => value !== null) - ).toString(); + const q = new URLSearchParams(); + if (version) q.set('version', version); + if (vim) q.set('vim', vim); throw redirect(301, `/repl/${id}?${q}`); } diff --git a/sites/svelte.dev/src/routes/(authed)/repl/[id]/AppControls.svelte b/sites/svelte.dev/src/routes/(authed)/repl/[id]/AppControls.svelte index 9f53f2ee89db..0a8ef19ea7d2 100644 --- a/sites/svelte.dev/src/routes/(authed)/repl/[id]/AppControls.svelte +++ b/sites/svelte.dev/src/routes/(authed)/repl/[id]/AppControls.svelte @@ -189,7 +189,7 @@ export default app;`
- e.target.select()} use:enter={(e) => e.target.blur()} /> + e.target.select()} use:enter={(e) => /** @type {HTMLInputElement} */ (e.target).blur()} />