From 5d1a029a54c20a66be94ddee39dbbb7d21c59869 Mon Sep 17 00:00:00 2001
From: Pascal Syma
Date: Thu, 21 Aug 2025 00:17:01 +0200
Subject: [PATCH] Add typecheck
---
.github/workflows/docker.yml | 2 ++
app/components/TeamJoinModal.vue | 1 +
app/components/admin/Answer.vue | 4 ++--
app/pages/hunt/[huntSlug]/admin.vue | 4 ++--
app/pages/hunt/[huntSlug]/pictures.vue | 8 +++++++-
bun.lock | 19 +++++++++++++------
package.json | 4 +++-
server/api/hunt/[huntId]/join.post.ts | 1 -
server/api/quest/[questId]/submit.post.ts | 6 +++---
shared/auth.d.ts | 3 ++-
shared/utils/slugcheck.test.ts | 1 +
shared/utils/slugcheck.ts | 15 ++++++++-------
12 files changed, 44 insertions(+), 24 deletions(-)
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 5c7ba8a..d76bd72 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -19,6 +19,8 @@ jobs:
run: bun run check
- name: ESLint
run: bun run lint
+ - name: Typecheck
+ run: bun run typecheck
- name: Run tests
run: bun run test
deploy:
diff --git a/app/components/TeamJoinModal.vue b/app/components/TeamJoinModal.vue
index 810aec9..00473aa 100644
--- a/app/components/TeamJoinModal.vue
+++ b/app/components/TeamJoinModal.vue
@@ -77,6 +77,7 @@ async function submit() {
Join a team
+
+ (newVal: boolean) =>
(formData.cloned.value!.start = newVal ? new Date() : null)
"
/>
@@ -227,7 +227,7 @@ async function addUser() {
label="End?"
:model-value="!!formData.cloned.value.end"
@update:model-value="
- (newVal) =>
+ (newVal: boolean) =>
(formData.cloned.value!.end = newVal ? new Date() : null)
"
/>
diff --git a/app/pages/hunt/[huntSlug]/pictures.vue b/app/pages/hunt/[huntSlug]/pictures.vue
index 61b9bce..88ff2d6 100644
--- a/app/pages/hunt/[huntSlug]/pictures.vue
+++ b/app/pages/hunt/[huntSlug]/pictures.vue
@@ -29,7 +29,13 @@ type Picture = {
const { data, refresh, error } = await useFetch(`/api/hunt/${id}/diashow`, {
transform: (input) => {
if (!input || input.quests.length <= 0)
- return { id: 0, name: '', cols: [] as Picture[][], count: 0 };
+ return {
+ id: 0,
+ name_de: '',
+ name_en: '',
+ cols: [] as Picture[][],
+ count: 0
+ };
const { quests, ...rest } = input;
const pictures: Picture[] = [];
diff --git a/bun.lock b/bun.lock
index f7dd715..dfd18c3 100644
--- a/bun.lock
+++ b/bun.lock
@@ -29,11 +29,12 @@
},
"devDependencies": {
"@nuxt/devtools": "^2.6.2",
+ "@types/bun": "^1.2.20",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.2.0",
"prettier-plugin-tailwindcss": "^0.6.14",
"prisma": "^6.13.0",
- "vue-tsc": "^3.0.4",
+ "vue-tsc": "^3.0.6",
},
},
},
@@ -542,6 +543,8 @@
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="],
+ "@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="],
+
"@types/bytes": ["@types/bytes@3.1.5", "", {}, "sha512-VgZkrJckypj85YxEsEavcMmmSOIzkUHqWmM4CCyia5dc54YwsXzJ5uT4fYxBQNEXx+oF1krlhgCbvfubXqZYsQ=="],
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
@@ -558,6 +561,8 @@
"@types/pluralize": ["@types/pluralize@0.0.33", "", {}, "sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg=="],
+ "@types/react": ["@types/react@19.1.10", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg=="],
+
"@types/resolve": ["@types/resolve@1.20.2", "", {}, "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q=="],
"@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="],
@@ -632,11 +637,11 @@
"@vitejs/plugin-vue-jsx": ["@vitejs/plugin-vue-jsx@5.0.1", "", { "dependencies": { "@babel/core": "^7.27.7", "@babel/plugin-transform-typescript": "^7.27.1", "@rolldown/pluginutils": "^1.0.0-beta.21", "@vue/babel-plugin-jsx": "^1.4.0" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", "vue": "^3.0.0" } }, "sha512-X7qmQMXbdDh+sfHUttXokPD0cjPkMFoae7SgbkF9vi3idGUKmxLcnU2Ug49FHwiKXebfzQRIm5yK3sfCJzNBbg=="],
- "@volar/language-core": ["@volar/language-core@2.4.20", "", { "dependencies": { "@volar/source-map": "2.4.20" } }, "sha512-dRDF1G33xaAIDqR6+mXUIjXYdu9vzSxlMGfMEwBxQsfY/JMUEXSpLTR057oTKlUQ2nIvCmP9k94A8h8z2VrNSA=="],
+ "@volar/language-core": ["@volar/language-core@2.4.23", "", { "dependencies": { "@volar/source-map": "2.4.23" } }, "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ=="],
- "@volar/source-map": ["@volar/source-map@2.4.20", "", {}, "sha512-mVjmFQH8mC+nUaVwmbxoYUy8cww+abaO8dWzqPUjilsavjxH0jCJ3Mp8HFuHsdewZs2c+SP+EO7hCd8Z92whJg=="],
+ "@volar/source-map": ["@volar/source-map@2.4.23", "", {}, "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q=="],
- "@volar/typescript": ["@volar/typescript@2.4.20", "", { "dependencies": { "@volar/language-core": "2.4.20", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Oc4DczPwQyXcVbd+5RsNEqX6ia0+w3p+klwdZQ6ZKhFjWoBP9PCPQYlKYRi/tDemWphW93P/Vv13vcE9I9D2GQ=="],
+ "@volar/typescript": ["@volar/typescript@2.4.23", "", { "dependencies": { "@volar/language-core": "2.4.23", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag=="],
"@vue-macros/common": ["@vue-macros/common@1.16.1", "", { "dependencies": { "@vue/compiler-sfc": "^3.5.13", "ast-kit": "^1.4.0", "local-pkg": "^1.0.0", "magic-string-ast": "^0.7.0", "pathe": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "vue": "^2.7.0 || ^3.2.25" }, "optionalPeers": ["vue"] }, "sha512-Pn/AWMTjoMYuquepLZP813BIcq8DTZiNCoaceuNlvaYuOTd8DqBZWc5u0uOMQZMInwME1mdSmmBAcTluiV9Jtg=="],
@@ -664,7 +669,7 @@
"@vue/devtools-shared": ["@vue/devtools-shared@7.7.7", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw=="],
- "@vue/language-core": ["@vue/language-core@3.0.4", "", { "dependencies": { "@volar/language-core": "2.4.20", "@vue/compiler-dom": "^3.5.0", "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", "alien-signals": "^2.0.5", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-BvueED4LfBCSNH66eeUQk37MQCb7hjdezzGgxniM0LbriW53AJIyLorgshAtStmjfsAuOCcTl/c1b+nz/ye8xQ=="],
+ "@vue/language-core": ["@vue/language-core@3.0.6", "", { "dependencies": { "@volar/language-core": "2.4.23", "@vue/compiler-dom": "^3.5.0", "@vue/compiler-vue2": "^2.7.16", "@vue/shared": "^3.5.0", "alien-signals": "^2.0.5", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-e2RRzYWm+qGm8apUHW1wA5RQxzNhkqbbKdbKhiDUcmMrNAZGyM8aTiL3UrTqkaFI5s7wJRGGrp4u3jgusuBp2A=="],
"@vue/reactivity": ["@vue/reactivity@3.5.18", "", { "dependencies": { "@vue/shared": "3.5.18" } }, "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg=="],
@@ -790,6 +795,8 @@
"builtin-modules": ["builtin-modules@5.0.0", "", {}, "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg=="],
+ "bun-types": ["bun-types@1.2.20", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-pxTnQYOrKvdOwyiyd/7sMt9yFOenN004Y6O4lCcCUoKVej48FS5cvTw9geRaEcB9TsDZaJKAxPTVvi8tFsVuXA=="],
+
"bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="],
"bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="],
@@ -2118,7 +2125,7 @@
"vue-router": ["vue-router@4.5.1", "", { "dependencies": { "@vue/devtools-api": "^6.6.4" }, "peerDependencies": { "vue": "^3.2.0" } }, "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw=="],
- "vue-tsc": ["vue-tsc@3.0.4", "", { "dependencies": { "@volar/typescript": "2.4.20", "@vue/language-core": "3.0.4" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-kZmSEjGtROApVBuaIcoprrXZsFNGon5ggkTJokmhQ/H1hMzCFRPQ0Ed8IHYFsmYJYvHBcdmEQVGVcRuxzPzNbw=="],
+ "vue-tsc": ["vue-tsc@3.0.6", "", { "dependencies": { "@volar/typescript": "2.4.23", "@vue/language-core": "3.0.6" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-Tbs8Whd43R2e2nxez4WXPvvdjGbW24rOSgRhLOHXzWiT4pcP4G7KeWh0YCn18rF4bVwv7tggLLZ6MJnO6jXPBg=="],
"vuestic-ui": ["vuestic-ui@1.10.3", "", { "dependencies": { "@floating-ui/vue": "^1.0.1", "@types/lodash": "^4.14.161", "cleave.js": "^1.6.0", "lodash": "^4.17.21" }, "peerDependencies": { "vue": "^3.0.4" } }, "sha512-E8Y6E7dg08+yrN+0UfIb7pffH6dX9hBrLhjTR74w9T8iXlkw8t5ULPwnzIXxrTxPbk/HvDDs1s++bMw/S0OFmA=="],
diff --git a/package.json b/package.json
index c4b21b3..5326260 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,7 @@
"test": "bun test",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
+ "typecheck": "nuxt typecheck",
"dev:up": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d",
"dev:down": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml down"
},
@@ -42,10 +43,11 @@
},
"devDependencies": {
"@nuxt/devtools": "^2.6.2",
+ "@types/bun": "^1.2.20",
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.2.0",
"prettier-plugin-tailwindcss": "^0.6.14",
"prisma": "^6.13.0",
- "vue-tsc": "^3.0.4"
+ "vue-tsc": "^3.0.6"
}
}
diff --git a/server/api/hunt/[huntId]/join.post.ts b/server/api/hunt/[huntId]/join.post.ts
index 803e29f..0eafa0d 100644
--- a/server/api/hunt/[huntId]/join.post.ts
+++ b/server/api/hunt/[huntId]/join.post.ts
@@ -1,4 +1,3 @@
-import { requireUserSession } from '#imports';
import { useValidatedBody, useValidatedParams, z, zh } from 'h3-zod';
import prisma from '~~/lib/prisma';
diff --git a/server/api/quest/[questId]/submit.post.ts b/server/api/quest/[questId]/submit.post.ts
index 8f4811e..cebff88 100644
--- a/server/api/quest/[questId]/submit.post.ts
+++ b/server/api/quest/[questId]/submit.post.ts
@@ -76,11 +76,11 @@ export default defineEventHandler(async (event) => {
if (quest.hunt.teams.length <= 0) {
throw createError({ status: 403, statusText: 'No team yet!' });
}
- if (quest.answers.length > 0 && quest.answers[0].final) {
+ if (quest.answers.length > 0 && quest.answers![0]?.final) {
throw createError({ status: 418, statusText: 'Already marked as final!' });
}
- const team = quest.hunt.teams[0];
+ const team = quest.hunt.teams![0]!;
const body = await readFormData(event);
const formDataObj = Object.fromEntries(body.entries());
@@ -101,7 +101,7 @@ export default defineEventHandler(async (event) => {
const prevAnswer =
quest.answers.length > 0
- ? quest.answers[0]
+ ? quest.answers![0]!
: {
updatedAt: null,
id: null
diff --git a/shared/auth.d.ts b/shared/auth.d.ts
index b392d5d..73ac5b3 100644
--- a/shared/auth.d.ts
+++ b/shared/auth.d.ts
@@ -1,7 +1,8 @@
import type { User as PUser } from '@prisma/client';
declare module '#auth-utils' {
- type User = Pick;
+ // eslint-disable-next-line
+ interface User extends Pick {}
interface UserSession {
user: User;
loggedInAt: string | Date;
diff --git a/shared/utils/slugcheck.test.ts b/shared/utils/slugcheck.test.ts
index ccaf151..a8ddbdf 100644
--- a/shared/utils/slugcheck.test.ts
+++ b/shared/utils/slugcheck.test.ts
@@ -1,3 +1,4 @@
+// @ts-expect-error weird bun import with nuxt
import { describe, expect, it } from 'bun:test';
import { checkSlug, parseSlug, type SlugRecord } from './slugcheck';
diff --git a/shared/utils/slugcheck.ts b/shared/utils/slugcheck.ts
index 4c787c4..81cc3a7 100644
--- a/shared/utils/slugcheck.ts
+++ b/shared/utils/slugcheck.ts
@@ -1,4 +1,4 @@
-import type { RouteParamsGeneric } from '#vue-router';
+import type { RouteParamsGeneric } from 'vue-router';
export type Slug = { name: string; id: number };
export type SlugRecord = Record;
@@ -16,12 +16,13 @@ export function parseSlug(slug: string): null | Slug {
const { name, id } = result.groups!;
return {
- name: name
- .substring(0, name.length - 1)
- .split('-')
- .map((w) => `${w.substring(0, 1).toUpperCase()}${w.substring(1)}`)
- .join(' '),
- id: parseInt(id)
+ name:
+ name
+ ?.substring(0, name.length - 1)
+ .split('-')
+ .map((w) => `${w.substring(0, 1).toUpperCase()}${w.substring(1)}`)
+ .join(' ') ?? '',
+ id: parseInt(id!)
};
}