1
1
mirror of https://github.com/go-gitea/gitea synced 2025-09-15 21:28:15 +00:00

Update eslint to v9 (#35485)

Update eslint and all plugins. Many plugins still do not ship type
definitions so I had to add stubs. Also, I had to put a few typescript
error expectations because if some unknown error in the types.

`eslint-plugin-no-jquery` is disabled because it's not compatible with
eslint 9 flat config
(https://github.com/wikimedia/eslint-plugin-no-jquery/issues/311).
This commit is contained in:
silverwind
2025-09-14 18:15:06 +02:00
committed by GitHub
parent e612b9744c
commit 69e595cdd8
29 changed files with 1493 additions and 1453 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -162,7 +162,7 @@ TAR_EXCLUDES := .git data indexers queues log node_modules $(EXECUTABLE) $(DIST)
GO_DIRS := build cmd models modules routers services tests GO_DIRS := build cmd models modules routers services tests
WEB_DIRS := web_src/js web_src/css WEB_DIRS := web_src/js web_src/css
ESLINT_FILES := web_src/js tools *.ts *.cjs tests/e2e ESLINT_FILES := web_src/js tools *.ts tests/e2e
STYLELINT_FILES := web_src/css web_src/js/components/*.vue STYLELINT_FILES := web_src/css web_src/js/components/*.vue
SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*)) SPELLCHECK_FILES := $(GO_DIRS) $(WEB_DIRS) templates options/locale/locale_en-US.ini .github $(filter-out CHANGELOG.md, $(wildcard *.go *.md *.yml *.yaml *.toml)) $(filter-out tools/misspellings.csv, $(wildcard tools/*))
EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini EDITORCONFIG_FILES := templates .github/workflows options/locale/locale_en-US.ini
@@ -346,12 +346,12 @@ lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backen
.PHONY: lint-js .PHONY: lint-js
lint-js: node_modules ## lint js files lint-js: node_modules ## lint js files
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) $(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES)
$(NODE_VARS) pnpm exec vue-tsc $(NODE_VARS) pnpm exec vue-tsc
.PHONY: lint-js-fix .PHONY: lint-js-fix
lint-js-fix: node_modules ## lint js files and fix issues lint-js-fix: node_modules ## lint js files and fix issues
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --ext js,ts,vue $(ESLINT_FILES) --fix $(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES) --fix
$(NODE_VARS) pnpm exec vue-tsc $(NODE_VARS) pnpm exec vue-tsc
.PHONY: lint-css .PHONY: lint-css

1029
eslint.config.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -69,7 +69,7 @@
"@eslint-community/eslint-plugin-eslint-comments": "4.5.0", "@eslint-community/eslint-plugin-eslint-comments": "4.5.0",
"@playwright/test": "1.55.0", "@playwright/test": "1.55.0",
"@stoplight/spectral-cli": "6.15.0", "@stoplight/spectral-cli": "6.15.0",
"@stylistic/eslint-plugin-js": "3.1.0", "@stylistic/eslint-plugin": "5.3.1",
"@stylistic/stylelint-plugin": "4.0.0", "@stylistic/stylelint-plugin": "4.0.0",
"@types/codemirror": "5.60.16", "@types/codemirror": "5.60.16",
"@types/dropzone": "5.7.9", "@types/dropzone": "5.7.9",
@@ -82,24 +82,24 @@
"@types/throttle-debounce": "5.0.2", "@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6", "@types/tinycolor2": "1.4.6",
"@types/toastify-js": "1.12.4", "@types/toastify-js": "1.12.4",
"@typescript-eslint/eslint-plugin": "8.43.0",
"@typescript-eslint/parser": "8.43.0", "@typescript-eslint/parser": "8.43.0",
"@vitejs/plugin-vue": "6.0.1", "@vitejs/plugin-vue": "6.0.1",
"@vitest/eslint-plugin": "1.3.9", "@vitest/eslint-plugin": "1.3.9",
"eslint": "8.57.0", "eslint": "9.35.0",
"eslint-import-resolver-typescript": "4.4.4", "eslint-import-resolver-typescript": "4.4.4",
"eslint-plugin-array-func": "4.0.0", "eslint-plugin-array-func": "5.0.2",
"eslint-plugin-github": "5.0.2", "eslint-plugin-github": "6.0.0",
"eslint-plugin-import-x": "4.16.1", "eslint-plugin-import-x": "4.16.1",
"eslint-plugin-no-jquery": "3.1.1", "eslint-plugin-no-jquery": "3.1.1",
"eslint-plugin-no-use-extend-native": "0.5.0", "eslint-plugin-no-use-extend-native": "0.7.2",
"eslint-plugin-playwright": "2.2.2", "eslint-plugin-playwright": "2.2.2",
"eslint-plugin-regexp": "2.10.0", "eslint-plugin-regexp": "2.10.0",
"eslint-plugin-sonarjs": "3.0.5", "eslint-plugin-sonarjs": "3.0.5",
"eslint-plugin-unicorn": "56.0.1", "eslint-plugin-unicorn": "61.0.2",
"eslint-plugin-vue": "10.4.0", "eslint-plugin-vue": "10.4.0",
"eslint-plugin-vue-scoped-css": "2.12.0", "eslint-plugin-vue-scoped-css": "2.12.0",
"eslint-plugin-wc": "3.0.1", "eslint-plugin-wc": "3.0.1",
"globals": "16.4.0",
"happy-dom": "18.0.1", "happy-dom": "18.0.1",
"markdownlint-cli": "0.45.0", "markdownlint-cli": "0.45.0",
"material-icon-theme": "5.27.0", "material-icon-theme": "5.27.0",
@@ -112,6 +112,7 @@
"stylelint-value-no-unknown-custom-properties": "6.0.1", "stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "4.0.0", "svgo": "4.0.0",
"type-fest": "4.41.0", "type-fest": "4.41.0",
"typescript-eslint": "8.43.0",
"updates": "16.7.0", "updates": "16.7.0",
"vite-string-plugin": "1.4.6", "vite-string-plugin": "1.4.6",
"vitest": "3.2.4", "vitest": "3.2.4",

789
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

27
types.d.ts vendored
View File

@@ -1,4 +1,29 @@
declare module '@techknowlogick/license-checker-webpack-plugin' { declare module '@techknowlogick/license-checker-webpack-plugin' {
const plugin: any; const plugin: any;
export = plugin export = plugin;
}
declare module 'eslint-plugin-no-use-extend-native' {
import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin;
export = plugin;
}
declare module 'eslint-plugin-array-func' {
import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin;
export = plugin;
}
declare module 'eslint-plugin-github' {
import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin;
export = plugin;
}
declare module 'eslint-plugin-no-jquery' {
import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin;
export = plugin;
}
declare module '@eslint-community/eslint-plugin-eslint-comments' {
import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin;
export = plugin;
} }

View File

@@ -5,12 +5,6 @@ export default {
'@mcaptcha/vanilla-glue', // breaking changes in rc versions need to be handled '@mcaptcha/vanilla-glue', // breaking changes in rc versions need to be handled
'@stylistic/eslint-plugin-js', // need to migrate to eslint 9 '@stylistic/eslint-plugin-js', // need to migrate to eslint 9
'cropperjs', // need to migrate to v2 but v2 is not compatible with v1 'cropperjs', // need to migrate to v2 but v2 is not compatible with v1
'eslint', // need to migrate to eslint flat config first
'eslint-plugin-array-func', // need to migrate to eslint flat config first
'eslint-plugin-github', // need to migrate to eslint 9 - https://github.com/github/eslint-plugin-github/issues/585
'eslint-plugin-no-use-extend-native', // need to migrate to eslint flat config first
'eslint-plugin-unicorn', // need to migrate to eslint 9
'eslint-plugin-vitest', // need to migrate to eslint flat config first
'tailwindcss', // need to migrate 'tailwindcss', // need to migrate
], ],
} satisfies Config; } satisfies Config;

View File

@@ -153,7 +153,7 @@ export default defineComponent({
return -1; return -1;
}, },
getActiveItem() { getActiveItem() {
const el = this.$refs[`listItem${this.activeItemIndex}`]; // eslint-disable-line no-jquery/variable-pattern const el = this.$refs[`listItem${this.activeItemIndex}`];
// @ts-expect-error - el is unknown type // @ts-expect-error - el is unknown type
return (el && el.length) ? el[0] : null; return (el && el.length) ? el[0] : null;
}, },

View File

@@ -19,7 +19,7 @@ type EditorConfig = {
trim_trailing_whitespace?: boolean, trim_trailing_whitespace?: boolean,
insert_final_newline?: boolean, insert_final_newline?: boolean,
root?: boolean, root?: boolean,
} };
const languagesByFilename: Record<string, string> = {}; const languagesByFilename: Record<string, string> = {};
const languagesByExt: Record<string, string> = {}; const languagesByExt: Record<string, string> = {};

View File

@@ -112,7 +112,7 @@ function onHidePanelClick(el: HTMLElement, e: MouseEvent) {
export type ElementWithAssignableProperties = { export type ElementWithAssignableProperties = {
getAttribute: (name: string) => string | null; getAttribute: (name: string) => string | null;
setAttribute: (name: string, value: string) => void; setAttribute: (name: string, value: string) => void;
} & Record<string, any> } & Record<string, any>;
export function assignElementProperty(el: ElementWithAssignableProperties, kebabName: string, val: string) { export function assignElementProperty(el: ElementWithAssignableProperties, kebabName: string, val: string) {
const camelizedName = camelize(kebabName); const camelizedName = camelize(kebabName);

View File

@@ -9,7 +9,7 @@ type ConfirmModalOptions = {
header?: string; header?: string;
content?: string; content?: string;
confirmButtonColor?: 'primary' | 'red' | 'green' | 'blue'; confirmButtonColor?: 'primary' | 'red' | 'green' | 'blue';
} };
export function createConfirmModal({header = '', content = '', confirmButtonColor = 'primary'}:ConfirmModalOptions = {}): HTMLElement { export function createConfirmModal({header = '', content = '', confirmButtonColor = 'primary'}:ConfirmModalOptions = {}): HTMLElement {
const headerHtml = header ? html`<div class="header">${header}</div>` : ''; const headerHtml = header ? html`<div class="header">${header}</div>` : '';

View File

@@ -4,7 +4,7 @@ type CropperOpts = {
container: HTMLElement, container: HTMLElement,
imageSource: HTMLImageElement, imageSource: HTMLImageElement,
fileInput: HTMLInputElement, fileInput: HTMLInputElement,
} };
async function initCompCropper({container, fileInput, imageSource}: CropperOpts) { async function initCompCropper({container, fileInput, imageSource}: CropperOpts) {
const {default: Cropper} = await import(/* webpackChunkName: "cropperjs" */'cropperjs'); const {default: Cropper} = await import(/* webpackChunkName: "cropperjs" */'cropperjs');

View File

@@ -169,7 +169,7 @@ test('EditorMarkdown', () => {
type ValueWithCursor = string | { type ValueWithCursor = string | {
value: string; value: string;
pos: number; pos: number;
} };
const testInput = (input: ValueWithCursor, result: ValueWithCursor) => { const testInput = (input: ValueWithCursor, result: ValueWithCursor) => {
const intputValue = typeof input === 'string' ? input : input.value; const intputValue = typeof input === 'string' ? input : input.value;
const inputPos = typeof input === 'string' ? intputValue.length : input.pos; const inputPos = typeof input === 'string' ? intputValue.length : input.pos;

View File

@@ -18,7 +18,7 @@ type TextareaValueSelection = {
value: string; value: string;
selStart: number; selStart: number;
selEnd: number; selEnd: number;
} };
function handleIndentSelection(textarea: HTMLTextAreaElement, e: KeyboardEvent) { function handleIndentSelection(textarea: HTMLTextAreaElement, e: KeyboardEvent) {
const selStart = textarea.selectionStart; const selStart = textarea.selectionStart;
@@ -65,14 +65,14 @@ function handleIndentSelection(textarea: HTMLTextAreaElement, e: KeyboardEvent)
type MarkdownHandleIndentionResult = { type MarkdownHandleIndentionResult = {
handled: boolean; handled: boolean;
valueSelection?: TextareaValueSelection; valueSelection?: TextareaValueSelection;
} };
type TextLinesBuffer = { type TextLinesBuffer = {
lines: string[]; lines: string[];
lengthBeforePosLine: number; lengthBeforePosLine: number;
posLineIndex: number; posLineIndex: number;
inlinePos: number inlinePos: number
} };
export function textareaSplitLines(value: string, pos: number): TextLinesBuffer { export function textareaSplitLines(value: string, pos: number): TextLinesBuffer {
const lines = value.split('\n'); const lines = value.split('\n');

View File

@@ -4,13 +4,13 @@ type Processor = (el: HTMLElement) => string | HTMLElement | void;
type Processors = { type Processors = {
[tagName: string]: Processor; [tagName: string]: Processor;
} };
type ProcessorContext = { type ProcessorContext = {
elementIsFirst: boolean; elementIsFirst: boolean;
elementIsLast: boolean; elementIsLast: boolean;
listNestingLevel: number; listNestingLevel: number;
} };
function prepareProcessors(ctx:ProcessorContext): Processors { function prepareProcessors(ctx:ProcessorContext): Processors {
const processors: Processors = { const processors: Processors = {

View File

@@ -15,7 +15,7 @@ export type DiffTreeEntry = {
Children: DiffTreeEntry[], Children: DiffTreeEntry[],
FileIcon: string, FileIcon: string,
ParentEntry?: DiffTreeEntry, ParentEntry?: DiffTreeEntry,
} };
type DiffFileTreeData = { type DiffFileTreeData = {
TreeRoot: DiffTreeEntry, TreeRoot: DiffTreeEntry,
@@ -28,7 +28,7 @@ type DiffFileTree = {
fullNameMap?: Record<string, DiffTreeEntry> fullNameMap?: Record<string, DiffTreeEntry>
fileTreeIsVisible: boolean; fileTreeIsVisible: boolean;
selectedItem: string; selectedItem: string;
} };
let diffTreeStoreReactive: Reactive<DiffFileTree>; let diffTreeStoreReactive: Reactive<DiffFileTree>;
export function diffTreeStore() { export function diffTreeStore() {

View File

@@ -14,5 +14,4 @@ export function linkLabelAndInput(label: Element, input: Element) {
} }
} }
// eslint-disable-next-line no-jquery/variable-pattern
export const fomanticQuery = $; export const fomanticQuery = $;

View File

@@ -15,7 +15,7 @@ type ToastLevels = {
background: string, background: string,
duration: number, duration: number,
} }
} };
const levels: ToastLevels = { const levels: ToastLevels = {
info: { info: {

View File

@@ -7,4 +7,4 @@ export type FileRenderPlugin = {
// render file content // render file content
render: (container: HTMLElement, fileUrl: string, options?: any) => Promise<void>; render: (container: HTMLElement, fileUrl: string, options?: any) => Promise<void>;
} };

View File

@@ -4,7 +4,7 @@ export type MentionValue = {
name: string, name: string,
fullname: string, fullname: string,
avatar: string, avatar: string,
} };
export type Config = { export type Config = {
appUrl: string, appUrl: string,
@@ -20,7 +20,7 @@ export type Config = {
mentionValues?: MentionValue[], mentionValues?: MentionValue[],
mermaidMaxSourceCharacters: number, mermaidMaxSourceCharacters: number,
i18n: Record<string, string>, i18n: Record<string, string>,
} };
export type IntervalId = ReturnType<typeof setInterval>; export type IntervalId = ReturnType<typeof setInterval>;
@@ -35,21 +35,21 @@ export type RequestOpts = {
export type RepoOwnerPathInfo = { export type RepoOwnerPathInfo = {
ownerName: string, ownerName: string,
repoName: string, repoName: string,
} };
export type IssuePathInfo = { export type IssuePathInfo = {
ownerName: string, ownerName: string,
repoName: string, repoName: string,
pathType: string, pathType: string,
indexString?: string, indexString?: string,
} };
export type IssuePageInfo = { export type IssuePageInfo = {
repoLink: string, repoLink: string,
repoId: number, repoId: number,
issueNumber: number, issueNumber: number,
issueDependencySearchType: string, issueDependencySearchType: string,
} };
export type Issue = { export type Issue = {
id: number; id: number;
@@ -65,6 +65,6 @@ export type Issue = {
export type FomanticInitFunction = { export type FomanticInitFunction = {
settings?: Record<string, any>, settings?: Record<string, any>,
(...args: any[]): any, (...args: any[]): any,
} };
export type GitRefType = 'branch' | 'tag'; export type GitRefType = 'branch' | 'tag';

View File

@@ -117,7 +117,7 @@ test('GlobCompiler', async () => {
for (const c of golangCases) { for (const c of golangCases) {
const compiled = globCompile(c.pattern, c.separators); const compiled = globCompile(c.pattern, c.separators);
const msg = `pattern: ${c.pattern}, input: ${c.input}, separators: ${c.separators || '(none)'}, compiled: ${compiled.regexpPattern}`; const msg = `pattern: ${c.pattern}, input: ${c.input}, separators: ${c.separators || '(none)'}, compiled: ${compiled.regexpPattern}`;
// eslint-disable-next-line @vitest/valid-expect -- Unlike Jest, Vitest supports a message as the second argument // eslint-disable-next-line vitest/valid-expect -- Unlike Jest, Vitest supports a message as the second argument
expect(compiled.regexp.test(c.input), msg).toBe(c.matched); expect(compiled.regexp.test(c.input), msg).toBe(c.matched);
} }

View File

@@ -1,7 +1,7 @@
type PngChunk = { type PngChunk = {
name: string, name: string,
data: Uint8Array, data: Uint8Array,
} };
export async function pngChunks(blob: Blob): Promise<PngChunk[]> { export async function pngChunks(blob: Blob): Promise<PngChunk[]> {
const uint8arr = new Uint8Array(await blob.arrayBuffer()); const uint8arr = new Uint8Array(await blob.arrayBuffer());
@@ -27,7 +27,7 @@ export async function pngChunks(blob: Blob): Promise<PngChunk[]> {
type ImageInfo = { type ImageInfo = {
width?: number, width?: number,
dppx?: number, dppx?: number,
} };
/** decode a image and try to obtain width and dppx. It will never throw but instead /** decode a image and try to obtain width and dppx. It will never throw but instead
* return default values. */ * return default values. */

View File

@@ -47,11 +47,11 @@ export type DayData = {
additions: number, additions: number,
deletions: number, deletions: number,
commits: number, commits: number,
} };
export type DayDataObject = { export type DayDataObject = {
[timestamp: string]: DayData, [timestamp: string]: DayData,
} };
export function fillEmptyStartDaysWithZeroes(startDays: number[], data: DayDataObject): DayData[] { export function fillEmptyStartDaysWithZeroes(startDays: number[], data: DayDataObject): DayData[] {
const result: Record<string, any> = {}; const result: Record<string, any> = {};