This commit is contained in:
silverwind 2025-12-14 12:04:01 +01:00 committed by GitHub
commit f5d65e0edb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 399 additions and 391 deletions

View File

@ -339,12 +339,12 @@ lint-backend-fix: lint-go-fix lint-go-gitea-vet lint-editorconfig ## lint backen
.PHONY: lint-js
lint-js: node_modules ## lint js files
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES)
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 $(ESLINT_FILES)
$(NODE_VARS) pnpm exec vue-tsc
.PHONY: lint-js-fix
lint-js-fix: node_modules ## lint js files and fix issues
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 --flag unstable_native_nodejs_ts_config $(ESLINT_FILES) --fix
$(NODE_VARS) pnpm exec eslint --color --max-warnings=0 $(ESLINT_FILES) --fix
$(NODE_VARS) pnpm exec vue-tsc
.PHONY: lint-css

View File

@ -147,7 +147,7 @@ export default defineConfig([
'@stylistic/wrap-regex': [0],
'@stylistic/yield-star-spacing': [2, 'after'],
'@typescript-eslint/adjacent-overload-signatures': [0],
'@typescript-eslint/array-type': [0],
'@typescript-eslint/array-type': [2, {default: 'generic'}],
'@typescript-eslint/await-thenable': [2],
'@typescript-eslint/ban-ts-comment': [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}],
'@typescript-eslint/ban-tslint-comment': [0],
@ -215,7 +215,7 @@ export default defineConfig([
'@typescript-eslint/no-unnecessary-condition': [0],
'@typescript-eslint/no-unnecessary-qualifier': [0],
'@typescript-eslint/no-unnecessary-template-expression': [0],
'@typescript-eslint/no-unnecessary-type-arguments': [0],
'@typescript-eslint/no-unnecessary-type-arguments': [2],
'@typescript-eslint/no-unnecessary-type-assertion': [2],
'@typescript-eslint/no-unnecessary-type-constraint': [2],
'@typescript-eslint/no-unnecessary-type-conversion': [2],
@ -228,7 +228,7 @@ export default defineConfig([
'@typescript-eslint/no-unsafe-member-access': [0],
'@typescript-eslint/no-unsafe-return': [0],
'@typescript-eslint/no-unsafe-unary-minus': [2],
'@typescript-eslint/no-unused-expressions': [0],
'@typescript-eslint/no-unused-expressions': [2],
'@typescript-eslint/no-unused-private-class-members': [2],
'@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}],
'@typescript-eslint/no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true, typedefs: false, enums: false, ignoreTypeReferences: true}],
@ -584,7 +584,7 @@ export default defineConfig([
'no-unreachable': [2],
'no-unsafe-finally': [2],
'no-unsafe-negation': [2],
'no-unused-expressions': [2],
'no-unused-expressions': [0], // handled by @typescript-eslint/no-unused-expressions
'no-unused-labels': [2],
'no-unused-private-class-members': [0], // handled by @typescript-eslint/no-unused-private-class-members
'no-unused-vars': [0], // handled by @typescript-eslint/no-unused-vars

View File

@ -1,6 +1,6 @@
{
"type": "module",
"packageManager": "pnpm@10.24.0",
"packageManager": "pnpm@10.25.0",
"engines": {
"node": ">= 22.6.0",
"pnpm": ">= 10.0.0"
@ -12,7 +12,7 @@
"@citation-js/plugin-software-formats": "0.6.1",
"@github/markdown-toolbar-element": "2.2.3",
"@github/paste-markdown": "1.5.3",
"@github/relative-time-element": "4.5.1",
"@github/relative-time-element": "5.0.0",
"@github/text-expander-element": "2.9.2",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.21.1",
@ -21,7 +21,7 @@
"@techknowlogick/license-checker-webpack-plugin": "0.3.0",
"add-asset-webpack-plugin": "3.1.1",
"ansi_up": "6.0.6",
"asciinema-player": "3.12.1",
"asciinema-player": "3.13.2",
"chart.js": "4.5.1",
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0",
@ -35,25 +35,24 @@
"htmx.org": "2.0.8",
"idiomorph": "0.7.4",
"jquery": "3.7.1",
"katex": "0.16.25",
"katex": "0.16.27",
"mermaid": "11.12.2",
"mini-css-extract-plugin": "2.9.4",
"monaco-editor": "0.55.1",
"monaco-editor-webpack-plugin": "7.1.1",
"online-3d-viewer": "0.16.0",
"online-3d-viewer": "0.17.0",
"pdfobject": "2.3.1",
"perfect-debounce": "2.0.0",
"postcss": "8.5.6",
"postcss-loader": "8.2.0",
"sortablejs": "1.15.6",
"swagger-ui-dist": "5.30.3",
"swagger-ui-dist": "5.31.0",
"tailwindcss": "3.4.17",
"throttle-debounce": "5.0.2",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
"toastify-js": "1.12.0",
"tributejs": "5.1.3",
"typescript": "5.9.3",
"uint8-to-base64": "0.2.1",
"vanilla-colorful": "0.7.2",
"vue": "3.5.25",
@ -79,10 +78,10 @@
"@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6",
"@types/toastify-js": "1.12.4",
"@typescript-eslint/parser": "8.48.1",
"@vitejs/plugin-vue": "6.0.2",
"@vitest/eslint-plugin": "1.5.1",
"eslint": "9.39.1",
"@typescript-eslint/parser": "8.49.0",
"@vitejs/plugin-vue": "6.0.3",
"@vitest/eslint-plugin": "1.5.2",
"eslint": "9.39.2",
"eslint-import-resolver-typescript": "4.4.4",
"eslint-plugin-array-func": "5.1.0",
"eslint-plugin-github": "6.0.0",
@ -96,7 +95,8 @@
"eslint-plugin-wc": "3.0.2",
"globals": "16.5.0",
"happy-dom": "20.0.11",
"markdownlint-cli": "0.46.0",
"jiti": "2.6.1",
"markdownlint-cli": "0.47.0",
"material-icon-theme": "5.29.0",
"nolyfill": "1.0.44",
"postcss-html": "1.8.0",
@ -107,11 +107,12 @@
"stylelint-declaration-strict-value": "1.10.11",
"stylelint-value-no-unknown-custom-properties": "6.0.1",
"svgo": "4.0.0",
"typescript-eslint": "8.48.1",
"updates": "17.0.4",
"typescript": "5.9.3",
"typescript-eslint": "8.49.0",
"updates": "17.0.7",
"vite-string-plugin": "1.4.9",
"vitest": "4.0.15",
"vue-tsc": "3.1.5"
"vue-tsc": "3.1.8"
},
"browserslist": [
"defaults"

File diff suppressed because it is too large Load Diff

View File

@ -75,7 +75,7 @@ function getLanguage(filename: string): string {
return languagesByFilename[filename] || languagesByExt[extname(filename)] || 'plaintext';
}
function updateEditor(monaco: Monaco, editor: IStandaloneCodeEditor, filename: string, lineWrapExts: string[]): void {
function updateEditor(monaco: Monaco, editor: IStandaloneCodeEditor, filename: string, lineWrapExts: Array<string>): void {
editor.updateOptions(getFileBasedOptions(filename, lineWrapExts));
const model = editor.getModel();
if (!model) return;
@ -175,7 +175,7 @@ export async function createMonaco(textarea: HTMLTextAreaElement, filename: stri
return {monaco, editor};
}
function getFileBasedOptions(filename: string, lineWrapExts: string[]): MonacoOpts {
function getFileBasedOptions(filename: string, lineWrapExts: Array<string>): MonacoOpts {
return {
wordWrap: (lineWrapExts || []).includes(extname(filename)) ? 'on' : 'off',
};

View File

@ -78,7 +78,7 @@ type MarkdownHandleIndentionResult = {
};
type TextLinesBuffer = {
lines: string[];
lines: Array<string>;
lengthBeforePosLine: number;
posLineIndex: number;
inlinePos: number

View File

@ -6,7 +6,7 @@ import {createElementFromHTML, showElem, toggleElemClass} from '../utils/dom.ts'
import {html} from '../utils/html.ts';
import {basename} from '../utils.ts';
const plugins: FileRenderPlugin[] = [];
const plugins: Array<FileRenderPlugin> = [];
function initPluginsOnce(): void {
if (plugins.length) return;

View File

@ -57,7 +57,7 @@ function initRepoIssueListCheckboxes() {
const url = el.getAttribute('data-url')!;
let action = el.getAttribute('data-action')!;
let elementId = el.getAttribute('data-element-id')!;
const issueIDList: string[] = [];
const issueIDList: Array<string> = [];
for (const el of document.querySelectorAll('.issue-checkbox:checked')) {
issueIDList.push(el.getAttribute('data-issue-id')!);
}
@ -116,7 +116,7 @@ function initDropdownUserRemoteSearch(el: Element) {
};
type ProcessedResult = {value: string, name: string};
const processedResults: ProcessedResult[] = []; // to be used by dropdown to generate menu items
const processedResults: Array<ProcessedResult> = []; // to be used by dropdown to generate menu items
const syncItemFromInput = () => {
const inputVal = elSearchInput.value.trim();
elItemFromInput.setAttribute('data-value', inputVal);

View File

@ -29,7 +29,7 @@ export class IssueSidebarComboList {
elDropdown: HTMLElement;
elList: HTMLElement;
elComboValue: HTMLInputElement;
initialValues: string[];
initialValues: Array<string>;
container: HTMLElement;
constructor(container: HTMLElement) {

View File

@ -67,7 +67,7 @@ function initRepoIssueLabelFilter(elDropdown: HTMLElement) {
e.preventDefault();
e.stopPropagation();
const labelId = item.getAttribute('data-label-id')!;
let labelIds: string[] = queryLabels ? queryLabels.split(',') : [];
let labelIds: Array<string> = queryLabels ? queryLabels.split(',') : [];
labelIds = labelIds.filter((id) => Math.abs(parseInt(id)) !== Math.abs(parseInt(labelId)));
labelIds.push(`-${labelId}`);
url.searchParams.set('labels', labelIds.join(','));

View File

@ -60,7 +60,7 @@ interface Window {
_inited: boolean,
push: (e: ErrorEvent & PromiseRejectionEvent) => void | number,
},
codeEditors: any[], // export editor for customization
codeEditors: Array<any>, // export editor for customization
// various captcha plugins
grecaptcha: any,

View File

@ -12,7 +12,7 @@ export type DiffTreeEntry = {
DiffStatus: DiffStatus,
EntryMode: string,
IsViewed: boolean,
Children: DiffTreeEntry[] | null,
Children: Array<DiffTreeEntry> | null,
FileIcon: string,
ParentEntry?: DiffTreeEntry,
};

View File

@ -291,8 +291,8 @@ function attachDomEvents(dropdown: HTMLElement, focusable: HTMLElement, menu: HT
// * z-label
// when the "scope/*" are filtered out, we'd like to see "a-label" and "z-label" without the divider.
export function hideScopedEmptyDividers(container: Element) {
const visibleItems: Element[] = [];
const curScopeVisibleItems: Element[] = [];
const visibleItems: Array<Element> = [];
const curScopeVisibleItems: Array<Element> = [];
let curScope: string = '', lastVisibleScope: string = '';
const isDivider = (item: Element) => item.classList.contains('divider');
const isScopedDivider = (item: Element) => isDivider(item) && item.hasAttribute('data-scope');

View File

@ -1,5 +1,5 @@
export class InitPerformanceTracer {
results: {name: string, dur: number}[] = [];
results: Array<{name: string, dur: number}> = [];
recordCall(name: string, func: () => void) {
const start = performance.now();
func();
@ -13,7 +13,7 @@ export class InitPerformanceTracer {
}
}
export function callInitFunctions(functions: (() => any)[]): InitPerformanceTracer | null {
export function callInitFunctions(functions: Array<() => any>): InitPerformanceTracer | null {
// Start performance trace by accessing a URL by "https://localhost/?_ui_performance_trace=1" or "https://localhost/?key=value&_ui_performance_trace=1"
// It is a quick check, no side effect so no need to do slow URL parsing.
const perfTracer = !window.location.search.includes('_ui_performance_trace=1') ? null : new InitPerformanceTracer();

View File

@ -5,7 +5,7 @@ import type {InitPerformanceTracer} from './init.ts';
let globalSelectorObserverInited = false;
type SelectorHandler = {selector: string, handler: (el: HTMLElement) => void};
const selectorHandlers: SelectorHandler[] = [];
const selectorHandlers: Array<SelectorHandler> = [];
type GlobalEventFunc<T extends HTMLElement, E extends Event> = (el: T, e: E) => Promisable<void>;
const globalEventFuncs: Record<string, GlobalEventFunc<HTMLElement, Event>> = {};

View File

@ -170,7 +170,7 @@ export type SvgName = keyof typeof svgs;
// most of the SVG icons in assets couldn't be used directly.
// retrieve an HTML string for given SVG icon name, size and additional classes
export function svg(name: SvgName, size = 16, classNames?: string | string[]): string {
export function svg(name: SvgName, size = 16, classNames?: string | Array<string>): string {
const className = Array.isArray(classNames) ? classNames.join(' ') : classNames;
if (!(name in svgs)) throw new Error(`Unknown SVG icon: ${name}`);
if (size === 16 && !className) return svgs[name];

View File

@ -17,7 +17,7 @@ export type Config = {
pageData: Record<string, any>,
notificationSettings: Record<string, any>,
enableTimeTracking: boolean,
mentionValues?: MentionValue[],
mentionValues?: Array<MentionValue>,
mermaidMaxSourceCharacters: number,
i18n: Record<string, string>,
};
@ -70,7 +70,7 @@ export type Issue = {
export type FomanticInitFunction = {
settings?: Record<string, any>,
(...args: any[]): any,
(...args: Array<any>): any,
};
export type GitRefType = 'branch' | 'tag';

View File

@ -6,9 +6,9 @@ import {isInFrontendUnitTest} from './testhelper.ts';
type ArrayLikeIterable<T> = ArrayLike<T> & Iterable<T>; // for NodeListOf and Array
type ElementArg = Element | string | ArrayLikeIterable<Element> | ReturnType<typeof $>;
type ElementsCallback<T extends Element> = (el: T) => Promisable<any>;
type ElementsCallbackWithArgs = (el: Element, ...args: any[]) => Promisable<any>;
type ElementsCallbackWithArgs = (el: Element, ...args: Array<any>) => Promisable<any>;
function elementsCall(el: ElementArg, func: ElementsCallbackWithArgs, ...args: any[]): ArrayLikeIterable<Element> {
function elementsCall(el: ElementArg, func: ElementsCallbackWithArgs, ...args: Array<any>): ArrayLikeIterable<Element> {
if (typeof el === 'string' || el instanceof String) {
el = document.querySelectorAll(el as string);
}
@ -65,7 +65,7 @@ function applyElemsCallback<T extends Element>(elems: ArrayLikeIterable<T>, fn?:
export function queryElemSiblings<T extends Element>(el: Element, selector = '*', fn?: ElementsCallback<T>): ArrayLikeIterable<T> {
if (!el.parentNode) return [];
const elems = Array.from(el.parentNode.children) as T[];
const elems = Array.from(el.parentNode.children) as Array<T>;
return applyElemsCallback<T>(elems.filter((child: Element) => {
return child !== el && child.matches(selector);
}), fn);
@ -301,7 +301,7 @@ export function createElementFromHTML<T extends HTMLElement>(htmlString: string)
return div.firstChild as T;
}
export function createElementFromAttrs(tagName: string, attrs: Record<string, any> | null, ...children: (Node | string)[]): HTMLElement {
export function createElementFromAttrs(tagName: string, attrs: Record<string, any> | null, ...children: Array<Node | string>): HTMLElement {
const el = document.createElement(tagName);
for (const [key, value] of Object.entries(attrs || {})) {
if (value === undefined || value === null) continue;

View File

@ -2,7 +2,7 @@ import {readFile} from 'node:fs/promises';
import * as path from 'node:path';
import {globCompile} from './glob.ts';
async function loadGlobTestData(): Promise<{caseNames: string[], caseDataMap: Record<string, string>}> {
async function loadGlobTestData(): Promise<{caseNames: Array<string>, caseDataMap: Record<string, string>}> {
const fileContent = await readFile(path.join(import.meta.dirname, 'glob.test.txt'), 'utf8');
const fileLines = fileContent.split('\n');
const caseDataMap: Record<string, string> = {};

View File

@ -3,9 +3,9 @@ type PngChunk = {
data: Uint8Array,
};
export async function pngChunks(blob: Blob): Promise<PngChunk[]> {
export async function pngChunks(blob: Blob): Promise<Array<PngChunk>> {
const uint8arr = new Uint8Array(await blob.arrayBuffer());
const chunks: PngChunk[] = [];
const chunks: Array<PngChunk> = [];
if (uint8arr.length < 12) return chunks;
const view = new DataView(uint8arr.buffer);
if (view.getBigUint64(0) !== 9894494448401390090n) return chunks;

View File

@ -4,12 +4,12 @@ import type {Issue} from '../types.ts';
const maxMatches = 6;
function sortAndReduce<T>(map: Map<T, number>): T[] {
function sortAndReduce<T>(map: Map<T, number>): Array<T> {
const sortedMap = new Map(Array.from(map.entries()).sort((a, b) => a[1] - b[1]));
return Array.from(sortedMap.keys()).slice(0, maxMatches);
}
export function matchEmoji(queryText: string): string[] {
export function matchEmoji(queryText: string): Array<string> {
const query = queryText.toLowerCase().replaceAll('_', ' ');
if (!query) return emojis.slice(0, maxMatches).map((e) => e.aliases[0]);
@ -30,7 +30,7 @@ export function matchEmoji(queryText: string): string[] {
}
type MentionSuggestion = {value: string; name: string; fullname: string; avatar: string};
export function matchMention(queryText: string): MentionSuggestion[] {
export function matchMention(queryText: string): Array<MentionSuggestion> {
const query = queryText.toLowerCase();
// results is a map of weights, lower is better
@ -45,10 +45,10 @@ export function matchMention(queryText: string): MentionSuggestion[] {
return sortAndReduce(results);
}
export async function matchIssue(owner: string, repo: string, issueIndexStr: string, query: string): Promise<Issue[]> {
export async function matchIssue(owner: string, repo: string, issueIndexStr: string, query: string): Promise<Array<Issue>> {
const res = await GET(`${window.config.appSubUrl}/${owner}/${repo}/issues/suggestions?q=${encodeURIComponent(query)}`);
const issues: Issue[] = await res.json();
const issues: Array<Issue> = await res.json();
const issueNumber = parseInt(issueIndexStr);
// filter out issue with same id

View File

@ -11,7 +11,7 @@ dayjs.extend(utc);
* @param startDate The start date. Can take any type that dayjs accepts.
* @param endDate The end date. Can take any type that dayjs accepts.
*/
export function startDaysBetween(startDate: ConfigType, endDate: ConfigType): number[] {
export function startDaysBetween(startDate: ConfigType, endDate: ConfigType): Array<number> {
const start = dayjs.utc(startDate);
const end = dayjs.utc(endDate);
@ -22,7 +22,7 @@ export function startDaysBetween(startDate: ConfigType, endDate: ConfigType): nu
current = current.add(1, 'day');
}
const startDays: number[] = [];
const startDays: Array<number> = [];
while (current.isBefore(end)) {
startDays.push(current.valueOf());
current = current.add(1, 'week');
@ -53,7 +53,7 @@ export type DayDataObject = {
[timestamp: string]: DayData,
};
export function fillEmptyStartDaysWithZeroes(startDays: number[], data: DayDataObject): DayData[] {
export function fillEmptyStartDaysWithZeroes(startDays: Array<number>, data: DayDataObject): Array<DayData> {
const result: Record<string, any> = {};
for (const startDay of startDays) {

View File

@ -5,7 +5,7 @@ try {
} catch {
const intlNumberFormat = Intl.NumberFormat;
// @ts-expect-error - polyfill is incomplete
Intl.NumberFormat = function(locales: string | string[], options: Intl.NumberFormatOptions) {
Intl.NumberFormat = function(locales: string | Array<string>, options: Intl.NumberFormatOptions) {
if (options.style === 'unit') {
return {
format(value: number | bigint | string) {