diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..341a9d1de2 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +node_modules/ +build/ +coverage/ +.storybook/ +.vuepress/ \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index c70e255d50..78d0f9c836 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -130,6 +130,28 @@ "promise/no-multiple-resolved": "error" }, "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "tsconfigRootDir": ".", + "project": ["./tsconfig.json", "**/tsconfig.json"], + "ecmaVersion": "latest", + "parser": "@typescript-eslint/parser", + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:@typescript-eslint/strict" + ], + "rules": { + // allow explicitly defined dangling promises + "@typescript-eslint/no-floating-promises": ["error", { "ignoreVoid": true }], + "no-void": ["error", { "allowAsStatement": true }] + } + }, { "files": ["!*.json"], "plugins": ["prettier"], diff --git a/package.json b/package.json index 9145f780c3..75ad564ca4 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "storybook:build": "storybook build -o build/storybook", "storybook:test": "test-storybook", "test:lint": "npm run test:lint:eslint && npm run test:lint:remark && npm run test:lint:style && npm run test:lint:locales", - "test:lint:eslint": "eslint --ext .vue,.ts,.tsx,.js,.jsx,.json,.yml,.yaml --max-warnings 0 --ignore-path .gitignore .", + "test:lint:eslint": "eslint --ext .vue,.ts,.tsx,.js,.jsx,.json,.yml,.yaml --max-warnings 0 .", "test:lint:locales": "scripts/locales/locales.sh src/locales", "test:lint:remark": "remark . --quiet --frail", "test:lint:style": "stylelint --max-warnings 0 --ignore-path .gitignore \"**/*.{css,scss,vue,vuex}\"", diff --git a/renderer/_default.page.client.ts b/renderer/_default.page.client.ts index e76dd36eae..c0fddcd2f9 100644 --- a/renderer/_default.page.client.ts +++ b/renderer/_default.page.client.ts @@ -2,13 +2,13 @@ import { createApp } from './app' import type { PageContext, VikePageContext } from '#types/PageContext' -let app: ReturnType -async function render(pageContext: VikePageContext & PageContext) { - if (!app) { - app = createApp(pageContext).app - app.mount('#app') +let instance: ReturnType +/* async */ function render(pageContext: VikePageContext & PageContext) { + if (!instance) { + instance = createApp(pageContext) + instance.app.mount('#app') } else { - app.changePage(pageContext) + instance.app.changePage(pageContext) } } diff --git a/renderer/app.ts b/renderer/app.ts index ed415cf05c..6a8d2dcbb7 100644 --- a/renderer/app.ts +++ b/renderer/app.ts @@ -49,7 +49,9 @@ function createApp(pageContext: VikePageContext & PageContext, isClient = true) objectAssign(app, { changePage: (pageContext: VikePageContext & PageContext) => { Object.assign(pageContextReactive, pageContext) + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access rootComponent.Page = markRaw(pageContext.Page) + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access rootComponent.pageProps = markRaw(pageContext.pageProps || {}) }, }) diff --git a/renderer/plugins/vuetify.ts b/renderer/plugins/vuetify.ts index f2465a718b..c43e92f694 100644 --- a/renderer/plugins/vuetify.ts +++ b/renderer/plugins/vuetify.ts @@ -2,7 +2,7 @@ import '@mdi/font/css/materialdesignicons.css' // eslint-disable-next-line import/no-unassigned-import import 'vuetify/lib/styles/main.sass' -import { useI18n } from 'vue-i18n' +import { I18n, useI18n } from 'vue-i18n' import { createVuetify } from 'vuetify' // eslint-disable-next-line import/no-namespace import * as components from 'vuetify/lib/components/index.mjs' @@ -11,7 +11,7 @@ import * as directives from 'vuetify/lib/directives/index.mjs' import { createVueI18nAdapter } from 'vuetify/locale/adapters/vue-i18n' // eslint-disable-next-line @typescript-eslint/no-explicit-any -export default (i18n: any) => +export default (i18n: I18n, NonNullable, string, false>) => createVuetify({ locale: { adapter: createVueI18nAdapter({ i18n, useI18n }), diff --git a/server/index.ts b/server/index.ts index 4b897e8a43..715bcec73e 100644 --- a/server/index.ts +++ b/server/index.ts @@ -19,7 +19,7 @@ import { root } from './root.js' const isProduction = process.env.NODE_ENV === 'production' -startServer() +void startServer() async function startServer() { const app = express() @@ -52,6 +52,7 @@ async function startServer() { // Vike middleware. It should always be our last middleware (because it's a // catch-all middleware superseding any middleware placed after it). + // eslint-disable-next-line @typescript-eslint/no-misused-promises app.get('*', async (req, res, next) => { const pageContextInit = { urlOriginal: req.originalUrl, diff --git a/src/components/ClientOnly.test.ts b/src/components/ClientOnly.test.ts index c3cf785e80..fa34cb841d 100644 --- a/src/components/ClientOnly.test.ts +++ b/src/components/ClientOnly.test.ts @@ -6,7 +6,7 @@ import ClientOnly from './ClientOnly.vue' describe('ClientOnly', () => { const wrapper = mount(ClientOnly) - it('renders content if mounted', async () => { + it('renders content if mounted', () => { expect(wrapper.isVisible()).toBeTruthy() }) }) diff --git a/src/env.ts b/src/env.ts index 78efb03f17..5eccab82ee 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,7 +1,8 @@ const META = { - DEFAULT_TITLE: import.meta.env.PUBLIC_ENV__META__DEFAULT_TITLE ?? 'IT4C', + DEFAULT_TITLE: (import.meta.env.PUBLIC_ENV__META__DEFAULT_TITLE as string) ?? 'IT4C', DEFAULT_DESCRIPTION: - import.meta.env.PUBLIC_ENV__META__DEFAULT_DESCRIPTION ?? 'IT4C Frontend Boilerplate', + (import.meta.env.PUBLIC_ENV__META__DEFAULT_DESCRIPTION as string) ?? + 'IT4C Frontend Boilerplate', } export { META } diff --git a/src/pages/_error.page.test.ts b/src/pages/_error.page.test.ts index 24e3503e82..b0d76bc2cf 100644 --- a/src/pages/_error.page.test.ts +++ b/src/pages/_error.page.test.ts @@ -1,10 +1,11 @@ -import { mount } from '@vue/test-utils' +import { VueWrapper, mount } from '@vue/test-utils' import { describe, it, expect, beforeEach } from 'vitest' +import { ComponentPublicInstance } from 'vue' import ErrorPage from './_error.page.vue' describe('ErrorPage', () => { - let wrapper: typeof ErrorPage + let wrapper: VueWrapper>> const Wrapper = () => { return mount(ErrorPage) } diff --git a/src/pages/app/index.page.server.ts b/src/pages/app/index.page.server.ts index 4659fa0a02..11bcb3a335 100644 --- a/src/pages/app/index.page.server.ts +++ b/src/pages/app/index.page.server.ts @@ -2,7 +2,7 @@ import type { PageContextBuiltInServer } from 'vike/types' export { onBeforeRender } -async function onBeforeRender(pageContext: PageContextBuiltInServer) { +/* async */ function onBeforeRender(pageContext: PageContextBuiltInServer) { return { pageContext: { pageProps: pageContext.routeParams, diff --git a/src/stores/counter.test.ts b/src/stores/counter.test.ts index a4634abbbd..bc812060f3 100644 --- a/src/stores/counter.test.ts +++ b/src/stores/counter.test.ts @@ -1,5 +1,5 @@ import { setActivePinia, createPinia } from 'pinia' -import { describe, it, expect } from 'vitest' +import { describe, it, expect, beforeEach } from 'vitest' import { useCounterStore } from './counter' diff --git a/src/stories/ExampleHeader.stories.ts b/src/stories/ExampleHeader.stories.ts index b35d3f9436..71130705a3 100644 --- a/src/stories/ExampleHeader.stories.ts +++ b/src/stories/ExampleHeader.stories.ts @@ -13,6 +13,7 @@ const meta = { render: (args: any) => ({ components: { ExampleHeader }, setup() { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment return { args } }, template: '', diff --git a/src/stories/ExamplePage.stories.ts b/src/stories/ExamplePage.stories.ts index 50f1c68bf9..4906d4a617 100644 --- a/src/stories/ExamplePage.stories.ts +++ b/src/stories/ExamplePage.stories.ts @@ -26,8 +26,8 @@ type Story = StoryObj export const LoggedIn: Story = { // eslint-disable-next-line @typescript-eslint/no-explicit-any play: async ({ canvasElement }: any) => { - const canvas = within(canvasElement) - const loginButton = await canvas.getByRole('button', { + const canvas = within(canvasElement as HTMLElement) + const loginButton = canvas.getByRole('button', { name: /Log in/i, }) await userEvent.click(loginButton) diff --git a/types/vue.d.ts b/types/vue.d.ts index fdd026a73a..5596f90ef3 100644 --- a/types/vue.d.ts +++ b/types/vue.d.ts @@ -1,5 +1,5 @@ declare module '*.vue' { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const Component: any - export default Component + import Vue from 'vue' + + export default Vue }