build: migrate eslint to v10 flat config and upgrade typescript
Replace .eslintrc.json with eslint.config.js using the new flat config format required by ESLint 10. Swap @typescript-eslint/eslint-plugin and @typescript-eslint/parser for the unified typescript-eslint package. Upgrade TypeScript to 5.9 and @types/node to 25. Apply automatic code fixes: remove unused catch bindings and preserve error cause in auth header parsing.
This commit is contained in:
1 parent
4a191afdec
commit
75908e624f
27 files changed
+1143
-1592
No files matched your search
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"es2022": true,
|
||||
"node": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"no-shadow": ["error", { "allow": ["err"] }],
|
||||
"handle-callback-err": "error",
|
||||
"prefer-arrow-callback": "error",
|
||||
"no-buffer-constructor": "error",
|
||||
"prefer-const": ["error", { "destructuring": "all" }],
|
||||
"eqeqeq": ["error", "always", { "null": "ignore" }],
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/no-use-before-define": [
|
||||
"error",
|
||||
{ "functions": false }
|
||||
],
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{ "allowExpressions": true }
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"no-prototype-builtins": 0
|
||||
}
|
||||
}
|
||||
@@ -55,6 +55,7 @@ process.on("message", (message) => {
|
||||
if (!script) {
|
||||
const cwd = process.env["GENIEACS_EXT_DIR"];
|
||||
process.chdir(cwd);
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
script = require(`${cwd}/${fileName}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { defineConfig } from "@eslint/config-helpers";
|
||||
import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import eslintConfigPrettier from "eslint-config-prettier";
|
||||
import globals from "globals";
|
||||
|
||||
export default defineConfig(
|
||||
{
|
||||
ignores: ["dist/", "test/*.js"],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
eslintConfigPrettier,
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.es2022,
|
||||
...globals.node,
|
||||
},
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"no-shadow": ["error", { allow: ["err"] }],
|
||||
"handle-callback-err": "error",
|
||||
"prefer-arrow-callback": "error",
|
||||
"no-buffer-constructor": "error",
|
||||
"prefer-const": ["error", { destructuring: "all" }],
|
||||
eqeqeq: ["error", "always", { null: "ignore" }],
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-use-before-define": [
|
||||
"error",
|
||||
{ functions: false },
|
||||
],
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error",
|
||||
{ allowExpressions: true },
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"no-prototype-builtins": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["ui/**/*.ts", "ui/**/*.tsx"],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -103,7 +103,7 @@ export async function connectionRequest(
|
||||
let remoteAddress;
|
||||
try {
|
||||
remoteAddress = new URL(connectionRequestUrl).hostname;
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return "Invalid connection request URL";
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ export async function connectionRequest(
|
||||
() => true,
|
||||
() => false,
|
||||
);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore invalid address
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ function parseHeaderFeilds(str: string): Record<string, string> {
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (error) {
|
||||
throw new Error("Unable to parse auth header");
|
||||
throw new Error("Unable to parse auth header", { cause: error });
|
||||
}
|
||||
}
|
||||
res[name.trim()] = value;
|
||||
|
||||
@@ -157,7 +157,7 @@ export async function httpConnectionRequest(
|
||||
authHeader = auth.parseWwwAuthenticateHeader(
|
||||
res.headers["www-authenticate"],
|
||||
);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return "Connection request error: Error parsing www-authenticate header";
|
||||
}
|
||||
[username, password, authExp] = await extractAuth(authExp, false);
|
||||
|
||||
+4
-4
@@ -89,7 +89,7 @@ async function authenticate(
|
||||
authentication = auth.parseAuthorizationHeader(
|
||||
sessionContext.httpRequest.headers["authorization"],
|
||||
);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1274,7 +1274,7 @@ async function clientError(
|
||||
body: string,
|
||||
msg: string,
|
||||
): Promise<void> {
|
||||
let debugEnabled = false;
|
||||
let debugEnabled: boolean;
|
||||
let deviceId: string = null;
|
||||
|
||||
if (sessionContext) {
|
||||
@@ -1312,7 +1312,7 @@ async function clientError(
|
||||
function decodeString(buffer: Buffer, charset: string): string {
|
||||
try {
|
||||
return buffer.toString(charset as BufferEncoding);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
if (encodingExists(charset)) return decode(buffer, charset);
|
||||
}
|
||||
return null;
|
||||
@@ -1383,7 +1383,7 @@ async function listenerAsync(
|
||||
// connection is closed before the stream is finished.
|
||||
// For Node 12.9+ we can just use stream.readableEnded
|
||||
if (!readableEnded) throw new Error("Connection closed");
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ export async function fetchDevice(
|
||||
|
||||
try {
|
||||
res.push([Path.parse(path), t, attrs]);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// The path parser is now more strict so we might be in a situation where
|
||||
// the database contains invalid paths from before this change So here we
|
||||
// encode the invalid characters.
|
||||
|
||||
@@ -82,7 +82,7 @@ async function fetchPresets(): Promise<[string, Preset[]]> {
|
||||
try {
|
||||
schedule.duration = +parts.shift() * 1000;
|
||||
schedule.schedule = scheduling.parseCron(parts.join(" "));
|
||||
} catch (err) {
|
||||
} catch {
|
||||
logger.warn({
|
||||
message: "Invalid preset schedule",
|
||||
preset: preset["_id"],
|
||||
@@ -97,7 +97,7 @@ async function fetchPresets(): Promise<[string, Preset[]]> {
|
||||
if (preset["precondition"]) {
|
||||
try {
|
||||
precondition = parse(preset["precondition"]);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
precondition = convertOldPrecondition(
|
||||
JSON.parse(preset["precondition"]),
|
||||
);
|
||||
|
||||
+2
-2
@@ -20,12 +20,12 @@ const cidrs: [IPv4 | IPv6, number][] = [];
|
||||
for (const str of FORWARDED_HEADER.split(",").map((s) => s.trim())) {
|
||||
try {
|
||||
cidrs.push(parseCIDR(str));
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Not a valid CIDR format, try parsing as IP
|
||||
try {
|
||||
const ip = parse(str);
|
||||
cidrs.push([ip, ip.toByteArray().length * 8]);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Not a valid IP either, ignore
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ function matchEtag(etag: string, header: string): boolean {
|
||||
if (t.startsWith("W/")) t = t.substring(2);
|
||||
try {
|
||||
t = JSON.parse(t);
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
if (t === "*") return true;
|
||||
|
||||
+1
-1
@@ -501,7 +501,7 @@ async function handler(
|
||||
};
|
||||
try {
|
||||
await filesBucket.delete(filename as unknown as ObjectId);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore error if file doesn't exist
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ export function start(
|
||||
res.writeHead(500, { Connection: "close" });
|
||||
res.end(`${err.name}: ${err.message}`);
|
||||
}
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
throw err;
|
||||
|
||||
+3
-3
@@ -119,7 +119,7 @@ function parameterInfoList(xml: Element): [Path, boolean, boolean][] {
|
||||
if (param && !param.endsWith("."))
|
||||
return [Path.parse(param), false, parsed];
|
||||
else return [Path.parse(param.slice(0, -1)), true, parsed];
|
||||
} catch (err) {
|
||||
} catch {
|
||||
warnings.push({
|
||||
message: "Missing or invalid XML node",
|
||||
element: "Name",
|
||||
@@ -201,7 +201,7 @@ function parameterValueList(
|
||||
}
|
||||
try {
|
||||
return [Path.parse(param), parsed, valueType];
|
||||
} catch (err) {
|
||||
} catch {
|
||||
warnings.push({
|
||||
message: "Missing or invalid XML node",
|
||||
element: "Name",
|
||||
@@ -250,7 +250,7 @@ function parameterAttributeList(xml: Element): [Path, number, string[]][] {
|
||||
|
||||
try {
|
||||
return [Path.parse(param), notification, accessList];
|
||||
} catch (err) {
|
||||
} catch {
|
||||
warnings.push({
|
||||
message: "Missing or invalid XML node",
|
||||
element: "Name",
|
||||
|
||||
+1
-1
@@ -519,7 +519,7 @@ router.put("/files/:id", async (ctx) => {
|
||||
|
||||
try {
|
||||
await db.deleteFile(id);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// File doesn't exist, ignore
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -260,7 +260,7 @@ function flattenPreset(
|
||||
try {
|
||||
// Try parse to check expression validity
|
||||
parse(p.precondition as string);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
p.precondition = convertOldPrecondition(
|
||||
JSON.parse(p.precondition as string),
|
||||
);
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ export function parseXmlDeclaration(buffer: Buffer): Attribute[] {
|
||||
str = str.slice(0, str.indexOf("?>"));
|
||||
try {
|
||||
return parseAttrs(str.slice(5));
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1047
-1514
File diff suppressed because it is too large.
Load diff
+6
-5
@@ -48,26 +48,27 @@
|
||||
"@codemirror/language": "^6.12.2",
|
||||
"@codemirror/state": "^6.5.4",
|
||||
"@codemirror/view": "^6.39.16",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tailwindcss/cli": "^4.2.1",
|
||||
"@tailwindcss/forms": "^0.5.11",
|
||||
"@types/jsonwebtoken": "^9.0.10",
|
||||
"@types/koa": "^2.15.0",
|
||||
"@types/koa-compress": "^4.0.7",
|
||||
"@types/mithril": "^2.2.7",
|
||||
"@types/node": "^20.19.37",
|
||||
"@types/node": "^25.3.5",
|
||||
"@types/parsimmon": "^1.10.9",
|
||||
"@types/seedrandom": "^3.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"esbuild": "^0.27.4",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-prettier": "^9.1.2",
|
||||
"eslint": "^10.0.3",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"globals": "^17.4.0",
|
||||
"mithril": "^2.3.8",
|
||||
"prettier": "^3.8.1",
|
||||
"sql.js": "^1.14.1",
|
||||
"svgo": "^3.3.3",
|
||||
"tailwindcss": "^4.2.1",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.56.1",
|
||||
"yaml": "^1.10.2"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": false
|
||||
}
|
||||
}
|
||||
@@ -119,7 +119,9 @@ export default class Autocomplete {
|
||||
if (!this.visible) {
|
||||
if (!this.hideTimeout) {
|
||||
document.body.appendChild(this.container);
|
||||
window.getComputedStyle(this.container).opacity;
|
||||
// Force style recalc so the initial opacity is resolved before
|
||||
// setting it to "1", allowing the CSS transition to play.
|
||||
void window.getComputedStyle(this.container).opacity;
|
||||
} else {
|
||||
clearTimeout(this.hideTimeout);
|
||||
this.hideTimeout = null;
|
||||
|
||||
@@ -47,7 +47,7 @@ const component: ClosureComponent = (vn): Component => {
|
||||
try {
|
||||
const url = new URL(param.value[0]);
|
||||
h = url.hostname;
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ function putActionHandler(action, _object, isNew?): Promise<ValidationErrors> {
|
||||
|
||||
try {
|
||||
object.value = stringify(parse(object.value || ""));
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return void resolve({
|
||||
value: "Config value must be valid expression",
|
||||
});
|
||||
|
||||
@@ -83,7 +83,7 @@ const component: ClosureComponent<Attrs> = (initialVnode) => {
|
||||
const list = filterList.map((f, idx) => {
|
||||
try {
|
||||
return parseFilter(attrs.resource, f);
|
||||
} catch (err) {
|
||||
} catch {
|
||||
filterInvalid |= 1 << idx;
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -90,7 +90,7 @@ function putActionHandler(action, _object, isNew): Promise<ValidationErrors> {
|
||||
if (object.filter) {
|
||||
try {
|
||||
object.filter = stringify(memoizedParse(object.filter));
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return void resolve({
|
||||
filter: "Filter must be valid expression",
|
||||
});
|
||||
@@ -100,7 +100,7 @@ function putActionHandler(action, _object, isNew): Promise<ValidationErrors> {
|
||||
if (object.validate) {
|
||||
try {
|
||||
object.validate = stringify(memoizedParse(object.validate));
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return void resolve({
|
||||
validate: "Validate must be valid expression",
|
||||
});
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ function putActionHandler(action, _object, isNew): Promise<ValidationErrors> {
|
||||
if (object.precondition) {
|
||||
try {
|
||||
object.precondition = stringify(memoizedParse(object.precondition));
|
||||
} catch (err) {
|
||||
} catch {
|
||||
return void resolve({
|
||||
precondition: "Precondition must be valid expression",
|
||||
});
|
||||
|
||||
+4
-2
@@ -113,7 +113,7 @@ function checkConnection(): void {
|
||||
setTimestamp(now2);
|
||||
m.redraw();
|
||||
}
|
||||
} catch (err) {
|
||||
} catch {
|
||||
// Ignore in case of missing or invalid Date header
|
||||
}
|
||||
|
||||
@@ -200,7 +200,9 @@ export async function xhrRequest(
|
||||
try {
|
||||
response = xhr.responseText ? JSON.parse(xhr.responseText) : null;
|
||||
} catch (err) {
|
||||
throw new Error("Invalid JSON: " + xhr.responseText.slice(0, 80));
|
||||
throw new Error("Invalid JSON: " + xhr.responseText.slice(0, 80), {
|
||||
cause: err,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
response = xhr.responseText;
|
||||
|
||||
Reference in new issue
Block a user