eslint: Unify JavaScript and TypeScript configs.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2025-02-26 16:29:52 -08:00
committed by Tim Abbott
parent 6f272d99d1
commit b3e0253eec
9 changed files with 73 additions and 80 deletions

View File

@@ -11,7 +11,7 @@ import tseslint from "typescript-eslint";
const compat = new FlatCompat({baseDirectory: import.meta.dirname});
export default [
export default tseslint.config(
{
files: ["tools/check-openapi"],
},
@@ -30,9 +30,15 @@ export default [
},
js.configs.recommended,
importPlugin.flatConfigs.recommended,
...compat.extends("plugin:no-jquery/recommended", "plugin:no-jquery/deprecated"),
compat.extends("plugin:no-jquery/recommended", "plugin:no-jquery/deprecated"),
unicorn.configs.recommended,
prettier,
tseslint.configs.strictTypeChecked,
tseslint.configs.stylisticTypeChecked,
{
files: ["**/*.cts", "**/*.mts", "**/*.ts"],
extends: [importPlugin.flatConfigs.typescript],
},
{
plugins: {
formatjs,
@@ -43,7 +49,12 @@ export default [
},
languageOptions: {
ecmaVersion: "latest",
globals: {
JQuery: "readonly",
},
parserOptions: {
projectService: true,
tsConfigRootDir: import.meta.dirname,
warnOnUnsupportedTypeScriptVersion: false,
},
},
@@ -51,17 +62,44 @@ export default [
formatjs: {
additionalFunctionNames: ["$t", "$t_html"],
},
"import/resolver": {
node: {
extensions: [".ts", ".d.ts", ".js"],
},
},
"no-jquery": {
collectionReturningPlugins: {expectOne: "always"},
variablePattern: "^\\$(?!t$|t_html$).",
},
},
rules: {
"@typescript-eslint/consistent-return": "error",
"@typescript-eslint/consistent-type-assertions": ["error", {assertionStyle: "never"}],
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/explicit-function-return-type": ["error", {allowExpressions: true}],
"@typescript-eslint/member-ordering": "error",
"@typescript-eslint/method-signature-style": "error",
"@typescript-eslint/no-loop-func": "error",
"@typescript-eslint/no-misused-spread": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unnecessary-condition": "off",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{args: "all", argsIgnorePattern: "^_", ignoreRestSiblings: true},
],
"@typescript-eslint/no-use-before-define": [
"error",
{functions: false, variables: false},
],
"@typescript-eslint/parameter-properties": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/restrict-plus-operands": ["error", {}],
"@typescript-eslint/restrict-template-expressions": ["error", {}],
"array-callback-return": "error",
"arrow-body-style": "error",
"consistent-return": "error",
curly: "error",
"dot-notation": "error",
eqeqeq: "error",
"formatjs/enforce-default-message": ["error", "literal"],
"formatjs/enforce-placeholders": [
@@ -83,7 +121,6 @@ export default [
"lines-around-directive": "error",
"new-cap": "error",
"no-alert": "error",
"no-array-constructor": "error",
"no-bitwise": "error",
"no-caller": "error",
"no-constant-condition": ["error", {checkLoops: false}],
@@ -91,13 +128,11 @@ export default [
"no-else-return": "error",
"no-eval": "error",
"no-implicit-coercion": "error",
"no-implied-eval": "error",
"no-jquery/no-append-html": "error",
"no-jquery/no-constructor-attributes": "error",
"no-jquery/no-parse-html-literal": "error",
"no-label-var": "error",
"no-labels": "error",
"no-loop-func": "error",
"no-multi-str": "error",
"no-new-func": "error",
"no-new-wrappers": "error",
@@ -109,17 +144,10 @@ export default [
"no-return-assign": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-throw-literal": "error",
"no-undef": "error",
"no-undef-init": "error",
"no-unneeded-ternary": ["error", {defaultAssignment: false}],
"no-unused-expressions": "error",
"no-unused-vars": [
"error",
{args: "all", argsIgnorePattern: "^_", ignoreRestSiblings: true},
],
"no-use-before-define": ["error", {functions: false, variables: false}],
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-var": "error",
"object-shorthand": ["error", "always", {avoidExplicitReturnArrows: true}],
"one-var": ["error", "never"],
@@ -147,6 +175,18 @@ export default [
yoda: "error",
},
},
{
ignores: ["**/*.cts", "**/*.mts", "**/*.ts"],
extends: [tseslint.configs.disableTypeChecked],
rules: {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-require-imports": "off",
"consistent-return": "error",
"dot-notation": "error",
"no-implied-eval": "error",
"no-throw-literal": "error",
},
},
{
files: ["**/*.cjs"],
languageOptions: {
@@ -156,7 +196,10 @@ export default [
{
files: ["web/tests/**"],
rules: {
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-extraneous-class": "off",
"no-jquery/no-selector-prop": "off",
"no-redeclare": "off",
},
},
{
@@ -167,59 +210,6 @@ export default [
},
},
},
...[
...tseslint.configs.strictTypeChecked,
...tseslint.configs.stylisticTypeChecked,
importPlugin.flatConfigs.typescript,
].map((config) => ({
...config,
files: ["**/*.cts", "**/*.mts", "**/*.ts"],
})),
{
files: ["**/*.cts", "**/*.mts", "**/*.ts"],
languageOptions: {
globals: {
JQuery: "readonly",
},
parserOptions: {
projectService: true,
tsConfigRootDir: import.meta.dirname,
},
},
settings: {
"import/resolver": {
node: {
extensions: [".ts", ".d.ts", ".js"],
},
},
},
rules: {
"no-use-before-define": "off",
"@typescript-eslint/consistent-type-assertions": ["error", {assertionStyle: "never"}],
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/explicit-function-return-type": ["error", {allowExpressions: true}],
"@typescript-eslint/member-ordering": "error",
"@typescript-eslint/method-signature-style": "error",
"@typescript-eslint/no-misused-spread": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unnecessary-condition": "off",
"@typescript-eslint/no-unnecessary-qualifier": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{args: "all", argsIgnorePattern: "^_", ignoreRestSiblings: true},
],
"@typescript-eslint/no-use-before-define": [
"error",
{functions: false, variables: false},
],
"@typescript-eslint/parameter-properties": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/restrict-plus-operands": ["error", {}],
"@typescript-eslint/restrict-template-expressions": ["error", {}],
"no-undef": "error",
},
},
{
files: ["**/*.d.ts"],
rules: {
@@ -227,7 +217,6 @@ export default [
},
},
{
files: ["**"],
ignores: ["web/shared/**", "web/src/**"],
languageOptions: {
globals: globals.node,
@@ -301,4 +290,4 @@ export default [
"unicorn/prefer-string-replace-all": "off",
},
},
];
);

View File

@@ -224,7 +224,7 @@ export let update_views_filtered_on_message_property = (
// can be used to update other message lists and
// cached message data structures as well.
},
// eslint-disable-next-line no-loop-func
// eslint-disable-next-line @typescript-eslint/no-loop-func
success(data) {
const parsed_data = z
.object({

View File

@@ -97,7 +97,10 @@ import * as user_topics from "./user_topics.ts";
import * as user_topics_ui from "./user_topics_ui.ts";
export function dispatch_normal_event(event) {
const noop = function () {};
const noop = function () {
// Do nothing
};
switch (event.type) {
case "alert_words":
alert_words.set_words(event.alert_words);

View File

@@ -250,7 +250,7 @@ export let upload_files = (
file_id,
true,
);
// eslint-disable-next-line no-loop-func
// eslint-disable-next-line @typescript-eslint/no-loop-func
config.upload_banner_cancel_button(file_id).one("click", () => {
compose_ui.replace_syntax(get_translated_status(file), "", config.textarea());
compose_ui.autosize_textarea(config.textarea());
@@ -259,7 +259,7 @@ export let upload_files = (
uppy.removeFile(file_id);
hide_upload_banner(uppy, config, file_id);
});
// eslint-disable-next-line no-loop-func
// eslint-disable-next-line @typescript-eslint/no-loop-func
config.upload_banner_hide_button(file_id).one("click", () => {
hide_upload_banner(uppy, config, file_id);
});

View File

@@ -251,12 +251,14 @@ exports.finish = function () {
for (const path of Object.keys(require.cache)) {
if (path.startsWith(webPath) && !path.startsWith(testsLibPath)) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete require.cache[path];
}
}
Object.assign(global, old_globals);
old_globals = {};
for (const name of new_globals) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete global[name];
}
new_globals.clear();
@@ -316,6 +318,7 @@ exports.with_overrides = function (test_function) {
if (had_value) {
obj[prop] = old_value;
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete obj[prop];
}
});

View File

@@ -3,6 +3,7 @@
const jquery = require("jquery");
// so the tests can mock jQuery
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete require.cache[require.resolve("jquery")];
module.exports = jquery;

View File

@@ -25,12 +25,7 @@ function FakeElement(selector, opts) {
const $self = {
length: 1,
[0]: {textContent: text},
*[Symbol.iterator]() {
// eslint-disable-next-line unicorn/no-for-loop
for (let i = 0; i < $self.length; i += 1) {
yield $self[i];
}
},
[Symbol.iterator]: Array.prototype.values,
addClass(class_name) {
classes.set(class_name, true);
return $self;

View File

@@ -5,6 +5,7 @@ exports.page_params = {};
exports.reset = () => {
for (const field in exports.page_params) {
if (Object.hasOwn(exports.page_params, field)) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete exports.page_params[field];
}
}

View File

@@ -5,6 +5,7 @@ exports.page_params = {};
exports.reset = () => {
for (const field in exports.page_params) {
if (Object.hasOwn(exports.page_params, field)) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete exports.page_params[field];
}
}