From 9a1c9a6b2c325afb1a903d6bf5baa6b98e6b516a Mon Sep 17 00:00:00 2001 From: Kuba Orlik Date: Sun, 17 Nov 2024 11:20:33 +0100 Subject: [PATCH] Fix lint and type errors --- package-lock.json | 8 ++++ package.json | 1 + src/back/collections/redirects.ts | 2 +- src/back/collections/user-roles.ts | 2 +- .../autoscrolling-images.stimulus.ts | 6 ++- .../map-with-pins/map-with-pins.stimulus.ts | 10 ++--- .../common/sortable/sortable.stimulus.ts | 20 ++++++---- src/back/routes/hello-page.page.tsx | 24 +++++++++++ src/back/routes/hello-page.test.ts | 40 +++++++++++++++++++ src/back/routes/login.form.ts | 1 - src/back/services/meilisearch.ts | 11 ++--- src/back/util.ts | 1 - src/front/index.ts | 2 + 13 files changed, 103 insertions(+), 25 deletions(-) create mode 100644 src/back/routes/hello-page.page.tsx create mode 100644 src/back/routes/hello-page.test.ts diff --git a/package-lock.json b/package-lock.json index 79bf613..7274899 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "devDependencies": { "@playwright/test": "^1.44.1", "@sealcode/ansi-html-stream": "^1.0.1", + "@types/hotwired__turbo": "^8.0.2", "@types/koa__router": "^12.0.4", "@types/node": "^20.8.4", "@types/object-path": "^0.11.4", @@ -1149,6 +1150,13 @@ "version": "7946.0.14", "license": "MIT" }, + "node_modules/@types/hotwired__turbo": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@types/hotwired__turbo/-/hotwired__turbo-8.0.2.tgz", + "integrity": "sha512-fFWI/JNSTVKTPliSOV4fdeC3Kt3FUTbRYkvtF7QPCkqR51+AJWIiX0T5sJXwUnjL9j43tzfBXPZ2jEsBqw8/Bg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/http-assert": { "version": "1.5.5", "license": "MIT" diff --git a/package.json b/package.json index a13e9f1..13779df 100644 --- a/package.json +++ b/package.json @@ -109,6 +109,7 @@ "devDependencies": { "@playwright/test": "^1.44.1", "@sealcode/ansi-html-stream": "^1.0.1", + "@types/hotwired__turbo": "^8.0.2", "@types/koa__router": "^12.0.4", "@types/node": "^20.8.4", "@types/object-path": "^0.11.4", diff --git a/src/back/collections/redirects.ts b/src/back/collections/redirects.ts index c1af503..30b7955 100644 --- a/src/back/collections/redirects.ts +++ b/src/back/collections/redirects.ts @@ -1,5 +1,5 @@ import { Collection, FieldTypes, Policies } from "sealious"; -import { CRUDRoles, Roles } from "../policy-types/roles.js"; +import { CRUDRoles } from "../policy-types/roles.js"; export default class Redirects extends Collection { fields = { diff --git a/src/back/collections/user-roles.ts b/src/back/collections/user-roles.ts index d76e8c0..befb05d 100644 --- a/src/back/collections/user-roles.ts +++ b/src/back/collections/user-roles.ts @@ -5,7 +5,7 @@ import { Roles } from "../policy-types/roles.js"; export default class UserRoles extends Collection { name = "user-roles"; fields = { - role: new FieldTypes.Text(), + role: new FieldTypes.Text().setRequired(true), user: new FieldTypes.SingleReference("users"), }; diff --git a/src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts index 933a46b..0c17983 100644 --- a/src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts +++ b/src/back/jdd-components/autoscrolling-images/autoscrolling-images.stimulus.ts @@ -56,9 +56,11 @@ export default class AutoscrollingImages extends Controller { const nextButtonID = radioButtonIdPrefix + "-autoscrolling-images__radio-" + nextIndex; // eslint-disable-next-line @typescript-eslint/consistent-type-assertions - const nextButton = this.element.querySelector("#" + nextButtonID); + const nextButton: HTMLInputElement = this.element.querySelector( + "#" + nextButtonID + ); if (nextButton) { - (nextButton as HTMLInputElement).checked = true; + nextButton.checked = true; this.currentIndex = nextIndex; this.handleRadioChange(); } diff --git a/src/back/jdd-components/map-with-pins/map-with-pins.stimulus.ts b/src/back/jdd-components/map-with-pins/map-with-pins.stimulus.ts index 66046b5..09e949f 100644 --- a/src/back/jdd-components/map-with-pins/map-with-pins.stimulus.ts +++ b/src/back/jdd-components/map-with-pins/map-with-pins.stimulus.ts @@ -23,8 +23,8 @@ function parseCoords(s: string): [number, number] { return s.split(", ").map((x) => parseFloat(x)) as [number, number]; } -function decodeHTMLEntities(text) { - var entities = [ +function decodeHTMLEntities(text: string) { + const entities = [ ["amp", "&"], ["apos", "'"], ["#x27", "'"], @@ -37,7 +37,7 @@ function decodeHTMLEntities(text) { ["quot", '"'], ]; - for (var i = 0, max = entities.length; i < max; ++i) + for (let i = 0, max = entities.length; i < max; ++i) text = text.replace(new RegExp("&" + entities[i][0] + ";", "g"), entities[i][1]); return text; @@ -101,9 +101,7 @@ export default class MapWithPins extends Controller { // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const pins = JSON.parse( // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument - decodeHTMLEntities( - this.element.attributes["data-map-with-pins-pins-value"].value - ) + decodeHTMLEntities(this.element.getAttribute("data-map-with-pins-pins-value")) ) as Pin[]; pins.forEach((pin) => this.addPin(pin)); this.initiated = true; diff --git a/src/back/routes/common/sortable/sortable.stimulus.ts b/src/back/routes/common/sortable/sortable.stimulus.ts index 9280ba9..aed8dd2 100644 --- a/src/back/routes/common/sortable/sortable.stimulus.ts +++ b/src/back/routes/common/sortable/sortable.stimulus.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-for-in-array */ +/* eslint-disable @typescript-eslint/consistent-type-assertions */ import { Controller } from "stimulus"; async function sleep(time: number) { @@ -21,7 +23,7 @@ export default class Sortable extends Controller { setIndex(node: HTMLDivElement, index: number) { node.setAttribute("data-index", String(index)); - (node as HTMLDivElement).style.setProperty("--index", String(index)); + node.style.setProperty("--index", String(index)); } setupHoleListeners(hole: HTMLDivElement) { @@ -70,7 +72,7 @@ export default class Sortable extends Controller { this.setIndex(node as HTMLDivElement, index_of_drop_target); last_node_of_target_index = node; } - let next_to_correct = nodes_of_dropped_element_index[0].previousSibling; + const next_to_correct = nodes_of_dropped_element_index[0].previousSibling; const children = Array.from(next_to_correct.parentNode.childNodes); const children_to_correct = children.slice(2); for (const dom_index in children_to_correct) { @@ -104,15 +106,18 @@ export default class Sortable extends Controller { .querySelectorAll(".edge-detector") .forEach((detector: HTMLDivElement) => { let is_hovered = false; - detector.addEventListener("dragenter", async (e) => { + detector.addEventListener("dragenter", (e) => { e.preventDefault(); const target = e.target as HTMLDivElement; const step = parseInt(target.getAttribute("data-step")); is_hovered = true; - while (is_hovered && this.dragged_element) { - window.scrollTo(window.scrollX, window.scrollY + step); - await sleep(16); - } + void (async () => { + while (is_hovered && this.dragged_element) { + window.scrollTo(window.scrollX, window.scrollY + step); + // eslint-disable-next-line no-await-in-loop + await sleep(16); + } + })(); }); detector.addEventListener("dragover ", (e) => { @@ -121,7 +126,6 @@ export default class Sortable extends Controller { }); detector.addEventListener("dragleave", (e) => { - const target = e.target as HTMLDivElement; e.preventDefault(); is_hovered = false; }); diff --git a/src/back/routes/hello-page.page.tsx b/src/back/routes/hello-page.page.tsx new file mode 100644 index 0000000..34bf7f7 --- /dev/null +++ b/src/back/routes/hello-page.page.tsx @@ -0,0 +1,24 @@ +import type { Context } from "koa"; +import { TempstreamJSX } from "tempstream"; +import { Page } from "@sealcode/sealgen"; + +import html from "src/back/html.js"; + +export const actionName = "HelloPage"; + +export default new (class HelloPagePage extends Page { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async canAccess(_: Context) { + return { canAccess: true, message: "" }; + } + + async render(ctx: Context) { + return html({ + ctx: ctx, + title: "HelloPage", + body:
Hello world
, + description: "", + css_clumps: ["default", "forms"], + }); + } +})(); diff --git a/src/back/routes/hello-page.test.ts b/src/back/routes/hello-page.test.ts new file mode 100644 index 0000000..e87546a --- /dev/null +++ b/src/back/routes/hello-page.test.ts @@ -0,0 +1,40 @@ +import { withProdApp } from "../test_utils/with-prod-app.js"; +import { VERY_LONG_TEST_TIMEOUT, webhintURL } from "../test_utils/webhint.js"; +import { HelloPageURL } from "./urls.js"; +import { getBrowser } from "../test_utils/browser-creator.js"; +import type { Browser, BrowserContext, Page } from "@playwright/test"; + +describe("HelloPage webhint", () => { + it("doesn't crash", async function () { + return withProdApp(async ({ base_url, rest_api }) => { + await rest_api.get(HelloPageURL); + await webhintURL(base_url + HelloPageURL); + // alternatively you can use webhintHTML for faster but less precise scans + // or for scanning responses of requests that use some form of authorization: + // const response = await rest_api.get(HelloPageURL); + // await webhintHTML(response); + }); + }).timeout(VERY_LONG_TEST_TIMEOUT); +}); + +describe("HelloPage", () => { + let page: Page; + let browser: Browser; + let context: BrowserContext; + + beforeEach(async () => { + browser = await getBrowser(); + context = await browser.newContext(); + page = await context.newPage(); + }); + + afterEach(async () => { + await context.close(); + }); + + it("works as expected", async function () { + return withProdApp(async ({ base_url }) => { + await page.goto(base_url + HelloPageURL); + }); + }).timeout(VERY_LONG_TEST_TIMEOUT); +}); diff --git a/src/back/routes/login.form.ts b/src/back/routes/login.form.ts index aac1759..0b40e18 100644 --- a/src/back/routes/login.form.ts +++ b/src/back/routes/login.form.ts @@ -38,7 +38,6 @@ export default new (class LoginForm extends Form { async onSubmit(ctx: Context) { const body = ctx.$body; - console.log(body); if ( !hasShape({ username: predicates.string, password: predicates.string }, body) ) { diff --git a/src/back/services/meilisearch.ts b/src/back/services/meilisearch.ts index d3cd207..25a6e17 100644 --- a/src/back/services/meilisearch.ts +++ b/src/back/services/meilisearch.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/consistent-type-assertions */ import type { Context } from "koa"; import { MeiliSearch } from "meilisearch"; import type { CollectionItem } from "sealious"; @@ -31,10 +32,10 @@ export const createIndex = async (name: string) => { } }; -const indexes = {} as Record< +const indexes: Record< string, - { getItems: (ctx: Context, ids: string[]) => CollectionItem[] } ->; + { getItems: (ctx: Context, ids: string[]) => Promise } +> = {}; export async function search( ctx: Context, @@ -55,9 +56,9 @@ export async function search( const result = Object.fromEntries( await Promise.all( use_indexes.map(async (index_name, key) => { - const ids = results[key]!.hits.map((e) => e.id); + const ids = results[key]!.hits.map((e) => e.id as string); const items = await indexes[index_name]?.getItems(ctx, ids); - return [index_name, items]; + return [index_name, items]; }) ) ); diff --git a/src/back/util.ts b/src/back/util.ts index bb957e3..cb8b3e4 100644 --- a/src/back/util.ts +++ b/src/back/util.ts @@ -2,7 +2,6 @@ /* eslint-disable @typescript-eslint/consistent-type-assertions */ import type { Context } from "koa"; import qs from "qs"; -import { MEILISEARCH_HOST } from "./config.js"; export async function sleep(time: number) { return new Promise((resolve) => setTimeout(resolve, time)); diff --git a/src/front/index.ts b/src/front/index.ts index a49c564..16ce00b 100644 --- a/src/front/index.ts +++ b/src/front/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/consistent-type-assertions */ export * from "./controllers.js"; (function enableScrollPreservation() { @@ -23,6 +24,7 @@ export * from "./controllers.js"; addEventListener("turbo:visit", () => { /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any */ if (shouldPreserveScroll) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any (window as any).Turbo.navigator.currentVisit.scrolled = true; document.documentElement.scrollTop = scrollTop; }