diff --git a/.eslintignore b/.eslintignore index 1f2ae53f..219bb10b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ public/ coverage/ +dist/ diff --git a/.eslintrc.cjs b/.eslintrc.cjs index ca48b1ad..4b567364 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,14 +1,18 @@ -module.exports = { - root: true, +// @ts-check +const {defineConfig} = require("eslint-define-config"); + +const projects = defineConfig({ parserOptions: { - ecmaVersion: 2022, - }, - env: { - es6: true, - browser: true, - mocha: true, - node: true, + project: [ + "./tsconfig.json", + "./client/tsconfig.json", + "./server/tsconfig.json", + "./test/tsconfig.json", + ], }, +}).parserOptions.project; + +const baseRules = defineConfig({ rules: { "block-scoped-var": "error", curly: ["error", "all"], @@ -23,7 +27,6 @@ module.exports = { "no-else-return": "error", "no-implicit-globals": "error", "no-restricted-globals": ["error", "event", "fdescribe"], - "no-shadow": "error", "no-template-curly-in-string": "error", "no-unsafe-negation": "error", "no-useless-computed-key": "error", @@ -62,18 +65,127 @@ module.exports = { "spaced-comment": ["error", "always"], strict: "off", yoda: "error", + }, +}).rules; + +const vueRules = defineConfig({ + rules: { + "import/no-default-export": 0, + "import/unambiguous": 0, // vue SFC can miss script tags + "@typescript-eslint/prefer-readonly": 0, // can be used in template "vue/component-tags-order": [ "error", { order: ["template", "style", "script"], }, ], + "vue/multi-word-component-names": "off", "vue/no-mutating-props": "off", "vue/no-v-html": "off", "vue/require-default-prop": "off", "vue/v-slot-style": ["error", "longform"], - "vue/multi-word-component-names": "off", }, - plugins: ["vue"], - extends: ["eslint:recommended", "plugin:vue/recommended", "prettier"], -}; +}).rules; + +const tsRules = defineConfig({ + rules: { + // note you must disable the base rule as it can report incorrect errors + "no-shadow": "off", + "@typescript-eslint/no-shadow": ["error"], + }, +}).rules; + +const tsRulesTemp = defineConfig({ + rules: { + // TODO: eventually remove these + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-this-alias": "off", + "@typescript-eslint/no-unnecessary-type-assertion": "off", + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unused-vars": "off", + }, +}).rules; + +const tsTestRulesTemp = defineConfig({ + rules: { + // TODO: remove these + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/restrict-plus-operands": "off", + }, +}).rules; + +module.exports = defineConfig({ + root: true, + parserOptions: { + ecmaVersion: 2022, + }, + overrides: [ + { + files: ["**/*.ts", "**/*.vue"], + parser: "@typescript-eslint/parser", + parserOptions: { + tsconfigRootDir: __dirname, + project: projects, + extraFileExtensions: [".vue"], + }, + plugins: ["@typescript-eslint"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "prettier", + ], + rules: { + ...baseRules, + ...tsRules, + ...tsRulesTemp, + }, + }, + { + files: ["**/*.vue"], + parser: "vue-eslint-parser", + parserOptions: { + ecmaVersion: 2022, + ecmaFeatures: { + jsx: true, + }, + parser: "@typescript-eslint/parser", + tsconfigRootDir: __dirname, + project: projects, + }, + plugins: ["vue"], + extends: [ + "eslint:recommended", + "plugin:vue/vue3-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "prettier", + ], + rules: {...baseRules, ...tsRules, ...tsRulesTemp, ...vueRules}, + }, + { + files: ["./tests/**/*.ts"], + parser: "@typescript-eslint/parser", + rules: { + ...baseRules, + ...tsRules, + ...tsRulesTemp, + ...tsTestRulesTemp, + }, + }, + ], + env: { + es6: true, + browser: true, + mocha: true, + node: true, + }, + extends: ["eslint:recommended", "prettier"], + rules: baseRules, +}); diff --git a/.gitignore b/.gitignore index 348de645..2f36fb37 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ package-lock.json coverage/ public/ +dist/ diff --git a/.npmignore b/.npmignore index e902f20a..8df5322f 100644 --- a/.npmignore +++ b/.npmignore @@ -9,9 +9,9 @@ # Ignore client folder as it's being built into public/ folder # except for the specified files which are used by the server client/** -!client/js/constants.js -!client/js/helpers/ircmessageparser/findLinks.js -!client/js/helpers/ircmessageparser/cleanIrcMessage.js +!client/js/constants.ts +!client/js/helpers/ircmessageparser/findLinks.ts +!client/js/helpers/ircmessageparser/cleanIrcMessage.ts !client/index.html.tpl public/js/bundle.vendor.js.map @@ -22,3 +22,4 @@ appveyor.yml webpack.config*.js postcss.config.js renovate.json + diff --git a/.prettierignore b/.prettierignore index aa316e17..5dabdfae 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,9 +1,10 @@ coverage/ public/ +dist/ test/fixtures/.thelounge/logs/ test/fixtures/.thelounge/certificates/ test/fixtures/.thelounge/storage/ - +test/fixtures/.thelounge/sts-policies.json *.log *.png *.svg diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d401e0e3..6e4bf808 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,7 +3,8 @@ "EditorConfig.EditorConfig", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint", - "octref.vetur" + "Vue.volar", + "Vue.vscode-typescript-vue-plugin" ], "unwantedRecommendations": [] } diff --git a/.vscode/settings.json b/.vscode/settings.json index d80731df..a7e07398 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,10 @@ { "editor.formatOnSave": true, - "vetur.format.enable": false, "prettier.useEditorConfig": true, "prettier.requireConfig": true, "prettier.disableLanguages": [], - "prettier.packageManager": "yarn", "eslint.packageManager": "yarn", - "eslint.codeActionsOnSave.mode": "all" + "eslint.codeActionsOnSave.mode": "all", + "[typescript]": {"editor.defaultFormatter": "esbenp.prettier-vscode"}, + "[vue]": {"editor.defaultFormatter": "esbenp.prettier-vscode"} } diff --git a/README.md b/README.md index 8fb2fb62..31665ab7 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ The Lounge is the official and community-managed fork of [Shout](https://github. ## Installation and usage The Lounge requires latest [Node.js](https://nodejs.org/) LTS version or more recent. -[Yarn package manager](https://yarnpkg.com/) is also recommended. +The [Yarn package manager](https://yarnpkg.com/) is also recommended. If you want to install with npm, `--unsafe-perm` is required for a correct install. ### Running stable releases @@ -85,5 +85,8 @@ Before submitting any change, make sure to: - Read the [Contributing instructions](https://github.com/thelounge/thelounge/blob/master/.github/CONTRIBUTING.md#contributing) - Run `yarn test` to execute linters and the test suite - Run `yarn format:prettier` if linting fails -- Run `yarn build` if you change or add anything in `client/js` or `client/components` +- Run `yarn build:client` if you change or add anything in `client/js` or `client/components` + - The built files will be output to `public/` by webpack +- Run `yarn build:server` if you change anything in `server/` + - The built files will be output to `dist/` by tsc - `yarn dev` can be used to start The Lounge with hot module reloading diff --git a/babel.config.cjs b/babel.config.cjs index 059d55ab..8554cbc5 100644 --- a/babel.config.cjs +++ b/babel.config.cjs @@ -1,3 +1,4 @@ module.exports = { - presets: [["@babel/env"]], + presets: [["@babel/preset-env", {bugfixes: true}], "babel-preset-typescript-vue3"], + plugins: ["@babel/plugin-transform-runtime"], }; diff --git a/client/components/App.vue b/client/components/App.vue index e02a10e7..61bbb3b7 100644 --- a/client/components/App.vue +++ b/client/components/App.vue @@ -1,13 +1,13 @@ - diff --git a/client/components/Channel.vue b/client/components/Channel.vue index 72551f9b..c21e55d2 100644 --- a/client/components/Channel.vue +++ b/client/components/Channel.vue @@ -1,4 +1,5 @@ - diff --git a/client/components/ChannelWrapper.vue b/client/components/ChannelWrapper.vue index 572881bc..380b52af 100644 --- a/client/components/ChannelWrapper.vue +++ b/client/components/ChannelWrapper.vue @@ -23,72 +23,90 @@ :data-type="channel.type" :aria-controls="'#chan-' + channel.id" :aria-selected="active" - :style="channel.closed ? {transition: 'none', opacity: 0.4} : null" + :style="channel.closed ? {transition: 'none', opacity: 0.4} : undefined" role="tab" @click="click" @contextmenu.prevent="openContextMenu" > - + - diff --git a/client/components/Chat.vue b/client/components/Chat.vue index 9838d1b6..f1dfc51b 100644 --- a/client/components/Chat.vue +++ b/client/components/Chat.vue @@ -3,10 +3,10 @@
@@ -95,7 +95,7 @@ {'scroll-down-shown': !channel.scrolledToBottom}, ]" aria-label="Jump to recent messages" - @click="$refs.messageList.jumpToBottom()" + @click="messageList?.jumpToBottom()" >
@@ -110,17 +110,17 @@
- {{ $store.state.currentUserVisibleError }} + {{ store.state.currentUserVisibleError }}
- diff --git a/client/components/ChatInput.vue b/client/components/ChatInput.vue index 401ee7ef..e89ef276 100644 --- a/client/components/ChatInput.vue +++ b/client/components/ChatInput.vue @@ -16,7 +16,7 @@ @blur="onBlur" /> - diff --git a/client/components/ChatUserList.vue b/client/components/ChatUserList.vue index 7eaa7c8b..ec3c971b 100644 --- a/client/components/ChatUserList.vue +++ b/client/components/ChatUserList.vue @@ -28,9 +28,10 @@
- diff --git a/client/components/ConfirmDialog.vue b/client/components/ConfirmDialog.vue index af92e368..17691cad 100644 --- a/client/components/ConfirmDialog.vue +++ b/client/components/ConfirmDialog.vue @@ -1,13 +1,13 @@ - diff --git a/client/components/JoinChannel.vue b/client/components/JoinChannel.vue index 129d5383..fa5eebc4 100644 --- a/client/components/JoinChannel.vue +++ b/client/components/JoinChannel.vue @@ -35,54 +35,59 @@ - diff --git a/client/components/LinkPreview.vue b/client/components/LinkPreview.vue index 9ae10b74..9a124ab8 100644 --- a/client/components/LinkPreview.vue +++ b/client/components/LinkPreview.vue @@ -129,137 +129,201 @@
- diff --git a/client/components/LinkPreviewFileSize.vue b/client/components/LinkPreviewFileSize.vue index 883df53d..5c577c1b 100644 --- a/client/components/LinkPreviewFileSize.vue +++ b/client/components/LinkPreviewFileSize.vue @@ -2,18 +2,21 @@ ({{ previewSize }}) - diff --git a/client/components/LinkPreviewToggle.vue b/client/components/LinkPreviewToggle.vue index 2b461066..24351ab7 100644 --- a/client/components/LinkPreviewToggle.vue +++ b/client/components/LinkPreviewToggle.vue @@ -7,23 +7,31 @@ /> - diff --git a/client/components/Mentions.vue b/client/components/Mentions.vue index 54759bff..63144948 100644 --- a/client/components/Mentions.vue +++ b/client/components/Mentions.vue @@ -20,20 +20,20 @@

Loading…

You have no recent mentions.

- - diff --git a/client/components/MessageList.vue b/client/components/MessageList.vue index cd298a6c..1c5ce9b5 100644 --- a/client/components/MessageList.vue +++ b/client/components/MessageList.vue @@ -3,7 +3,7 @@