Remove and forbid @ts-expect-error (#36513)

Removes `@ts-expect-error` in the code base and forbids it.

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: silverwind <115237+silverwind@users.noreply.github.com>
Co-authored-by: silverwind <me@silverwind.io>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Copilot
2026-02-02 01:00:34 +08:00
committed by GitHub
parent c2dea22926
commit 7883f6dde9
22 changed files with 170 additions and 117 deletions
+4 -5
View File
@@ -15,6 +15,7 @@ import vue from 'eslint-plugin-vue';
import vueScopedCss from 'eslint-plugin-vue-scoped-css'; import vueScopedCss from 'eslint-plugin-vue-scoped-css';
import wc from 'eslint-plugin-wc'; import wc from 'eslint-plugin-wc';
import {defineConfig, globalIgnores} from 'eslint/config'; import {defineConfig, globalIgnores} from 'eslint/config';
import type {ESLint} from 'eslint';
const jsExts = ['js', 'mjs', 'cjs'] as const; const jsExts = ['js', 'mjs', 'cjs'] as const;
const tsExts = ['ts', 'mts', 'cts'] as const; const tsExts = ['ts', 'mts', 'cts'] as const;
@@ -62,8 +63,7 @@ export default defineConfig([
'@stylistic': stylistic, '@stylistic': stylistic,
'@typescript-eslint': typescriptPlugin.plugin, '@typescript-eslint': typescriptPlugin.plugin,
'array-func': arrayFunc, 'array-func': arrayFunc,
// @ts-expect-error -- https://github.com/un-ts/eslint-plugin-import-x/issues/203 'import-x': importPlugin as unknown as ESLint.Plugin, // https://github.com/un-ts/eslint-plugin-import-x/issues/203
'import-x': importPlugin,
regexp, regexp,
sonarjs, sonarjs,
unicorn, unicorn,
@@ -156,7 +156,7 @@ export default defineConfig([
'@typescript-eslint/adjacent-overload-signatures': [0], '@typescript-eslint/adjacent-overload-signatures': [0],
'@typescript-eslint/array-type': [0], '@typescript-eslint/array-type': [0],
'@typescript-eslint/await-thenable': [2], '@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-ts-comment': [2, {'ts-expect-error': true, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}],
'@typescript-eslint/ban-tslint-comment': [0], '@typescript-eslint/ban-tslint-comment': [0],
'@typescript-eslint/class-literal-property-style': [0], '@typescript-eslint/class-literal-property-style': [0],
'@typescript-eslint/class-methods-use-this': [0], '@typescript-eslint/class-methods-use-this': [0],
@@ -924,8 +924,7 @@ export default defineConfig([
}, },
extends: [ extends: [
vue.configs['flat/recommended'], vue.configs['flat/recommended'],
// @ts-expect-error vueScopedCss.configs['flat/recommended'] as any,
vueScopedCss.configs['flat/recommended'],
], ],
rules: { rules: {
'vue/attributes-order': [0], 'vue/attributes-order': [0],
+1 -1
View File
@@ -13,7 +13,7 @@
"target": "es2020", "target": "es2020",
"module": "esnext", "module": "esnext",
"moduleResolution": "bundler", "moduleResolution": "bundler",
"lib": ["dom", "dom.iterable", "dom.asynciterable", "esnext"], "lib": ["dom", "dom.iterable", "dom.asynciterable", "esnext", "webworker"],
"allowImportingTsExtensions": true, "allowImportingTsExtensions": true,
"allowJs": true, "allowJs": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
Vendored
+87
View File
@@ -2,18 +2,105 @@ 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' { declare module 'eslint-plugin-no-use-extend-native' {
import type {Eslint} from 'eslint'; import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin; const plugin: Eslint.Plugin;
export = plugin; export = plugin;
} }
declare module 'eslint-plugin-array-func' { declare module 'eslint-plugin-array-func' {
import type {Eslint} from 'eslint'; import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin; const plugin: Eslint.Plugin;
export = plugin; export = plugin;
} }
declare module 'eslint-plugin-github' { declare module 'eslint-plugin-github' {
import type {Eslint} from 'eslint'; import type {Eslint} from 'eslint';
const plugin: Eslint.Plugin; const plugin: Eslint.Plugin;
export = plugin; export = plugin;
} }
declare module '*.svg' {
const value: string;
export default value;
}
declare module '*.css' {
const value: string;
export default value;
}
declare module '*.vue' {
import type {DefineComponent} from 'vue';
const component: DefineComponent<unknown, unknown, any>;
export default component;
// Here we declare all exports from vue files so `tsc` or `tsgo` can work for
// non-vue files. To lint .vue files, `vue-tsc` must be used.
export function initDashboardRepoList(): void;
export function initRepositoryActionView(): void;
}
declare module 'htmx.org/dist/htmx.esm.js' {
const value = await import('htmx.org');
export default value;
}
declare module 'swagger-ui-dist/swagger-ui-es-bundle.js' {
const value = await import('swagger-ui-dist');
export default value.SwaggerUIBundle;
}
declare module 'asciinema-player' {
interface AsciinemaPlayer {
create(src: string, element: HTMLElement, options?: Record<string, unknown>): void;
}
const exports: AsciinemaPlayer;
export = exports;
}
declare module '@citation-js/core' {
export class Cite {
constructor(data: string);
format(format: string, options?: Record<string, any>): string;
}
export const plugins: {
config: {
get(name: string): any;
};
};
}
declare module '@citation-js/plugin-software-formats' {}
declare module '@citation-js/plugin-bibtex' {}
declare module '@citation-js/plugin-csl' {}
declare module 'vue-bar-graph' {
import type {DefineComponent} from 'vue';
interface BarGraphPoint {
value: number;
label: string;
}
export const VueBarGraph: DefineComponent<{
points?: Array<BarGraphPoint>;
barColor?: string;
textColor?: string;
textAltColor?: string;
height?: number;
labelHeight?: number;
}>;
}
declare module '@mcaptcha/vanilla-glue' {
export let INPUT_NAME: string;
export default class Widget {
constructor(options: {
siteKey: {
instanceUrl: URL;
key: string;
};
});
}
}
+2 -3
View File
@@ -80,13 +80,12 @@ function initGlobalErrorHandler() {
// we added an event handler for window error at the very beginning of <script> of page head the // we added an event handler for window error at the very beginning of <script> of page head the
// handler calls `_globalHandlerErrors.push` (array method) to record all errors occur before // handler calls `_globalHandlerErrors.push` (array method) to record all errors occur before
// this init then in this init, we can collect all error events and show them. // this init then in this init, we can collect all error events and show them.
for (const e of window._globalHandlerErrors || []) { for (const e of (window._globalHandlerErrors as Iterable<ErrorEvent & PromiseRejectionEvent>) || []) {
processWindowErrorEvent(e); processWindowErrorEvent(e);
} }
// then, change _globalHandlerErrors to an object with push method, to process further error // then, change _globalHandlerErrors to an object with push method, to process further error
// events directly // events directly
// @ts-expect-error -- this should be refactored to not use a fake array window._globalHandlerErrors = {_inited: true, push: (e: ErrorEvent & PromiseRejectionEvent) => processWindowErrorEvent(e)} as any;
window._globalHandlerErrors = {_inited: true, push: (e: ErrorEvent & PromiseRejectionEvent) => processWindowErrorEvent(e)};
} }
initGlobalErrorHandler(); initGlobalErrorHandler();
+6 -5
View File
@@ -13,6 +13,8 @@ import {localUserSettings} from '../modules/user-settings.ts';
// see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts" // see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts"
type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked'; type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
type StepContainerElement = HTMLElement & {_stepLogsActiveContainer?: HTMLElement}
type LogLine = { type LogLine = {
index: number; index: number;
timestamp: number; timestamp: number;
@@ -221,19 +223,18 @@ export default defineComponent({
}, },
// get the job step logs container ('.job-step-logs') // get the job step logs container ('.job-step-logs')
getJobStepLogsContainer(stepIndex: number): HTMLElement { getJobStepLogsContainer(stepIndex: number): StepContainerElement {
return (this.$refs.logs as any)[stepIndex]; return (this.$refs.logs as any)[stepIndex];
}, },
// get the active logs container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group` // get the active logs container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group`
getActiveLogsContainer(stepIndex: number): HTMLElement { getActiveLogsContainer(stepIndex: number): StepContainerElement {
const el = this.getJobStepLogsContainer(stepIndex); const el = this.getJobStepLogsContainer(stepIndex);
// @ts-expect-error - _stepLogsActiveContainer is a custom property
return el._stepLogsActiveContainer ?? el; return el._stepLogsActiveContainer ?? el;
}, },
// begin a log group // begin a log group
beginLogGroup(stepIndex: number, startTime: number, line: LogLine, cmd: LogLineCommand) { beginLogGroup(stepIndex: number, startTime: number, line: LogLine, cmd: LogLineCommand) {
const el = (this.$refs.logs as any)[stepIndex]; const el = (this.$refs.logs as any)[stepIndex] as StepContainerElement;
const elJobLogGroupSummary = createElementFromAttrs('summary', {class: 'job-log-group-summary'}, const elJobLogGroupSummary = createElementFromAttrs('summary', {class: 'job-log-group-summary'},
this.createLogLine(stepIndex, startTime, { this.createLogLine(stepIndex, startTime, {
index: line.index, index: line.index,
@@ -395,7 +396,7 @@ export default defineComponent({
} }
// auto-scroll to the last log line of the last step // auto-scroll to the last log line of the last step
let autoScrollJobStepElement: HTMLElement | undefined; let autoScrollJobStepElement: StepContainerElement | undefined;
for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) { for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) {
if (!autoScrollStepIndexes.get(stepIndex)) continue; if (!autoScrollStepIndexes.get(stepIndex)) continue;
autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex); autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex);
@@ -1,5 +1,4 @@
<script lang="ts" setup> <script lang="ts" setup>
// @ts-expect-error - module exports no types
import {VueBarGraph} from 'vue-bar-graph'; import {VueBarGraph} from 'vue-bar-graph';
import {computed, onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue'; import {computed, onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue';
@@ -155,9 +155,8 @@ export default defineComponent({
return -1; return -1;
}, },
getActiveItem() { getActiveItem() {
const el = this.$refs[`listItem${this.activeItemIndex}`]; const el = this.$refs[`listItem${this.activeItemIndex}`] as Array<HTMLDivElement>;
// @ts-expect-error - el is unknown type return el?.length ? el[0] : null;
return (el && el.length) ? el[0] : null;
}, },
keydown(e: KeyboardEvent) { keydown(e: KeyboardEvent) {
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') { if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
@@ -174,7 +173,7 @@ export default defineComponent({
return; return;
} }
this.activeItemIndex = nextIndex; this.activeItemIndex = nextIndex;
this.getActiveItem().scrollIntoView({block: 'nearest'}); this.getActiveItem()!.scrollIntoView({block: 'nearest'});
} else if (e.key === 'Enter') { } else if (e.key === 'Enter') {
e.preventDefault(); e.preventDefault();
this.getActiveItem()?.click(); this.getActiveItem()?.click();
+10 -2
View File
@@ -41,6 +41,15 @@ const customEventListener: Plugin = {
}, },
}; };
type LineOptions = ChartOptions<'line'> & {
plugins?: {
customEventListener?: {
chartType: string;
instance: unknown;
};
};
}
Chart.defaults.color = chartJsColors.text; Chart.defaults.color = chartJsColors.text;
Chart.defaults.borderColor = chartJsColors.border; Chart.defaults.borderColor = chartJsColors.border;
@@ -251,7 +260,7 @@ export default defineComponent({
} }
}, },
getOptions(type: string): ChartOptions<'line'> { getOptions(type: string): LineOptions {
return { return {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
@@ -264,7 +273,6 @@ export default defineComponent({
position: 'top', position: 'top',
align: 'center', align: 'center',
}, },
// @ts-expect-error: bug in chart.js types
customEventListener: { customEventListener: {
chartType: type, chartType: type,
instance: this, instance: this,
+2 -2
View File
@@ -8,6 +8,7 @@ import {
TimeScale, TimeScale,
type ChartOptions, type ChartOptions,
type ChartData, type ChartData,
type ChartDataset,
} from 'chart.js'; } from 'chart.js';
import {GET} from '../modules/fetch.ts'; import {GET} from '../modules/fetch.ts';
import {Bar} from 'vue-chartjs'; import {Bar} from 'vue-chartjs';
@@ -83,13 +84,12 @@ function toGraphData(data: DayData[]): ChartData<'bar'> {
return { return {
datasets: [ datasets: [
{ {
// @ts-expect-error -- bar chart expects one-dimensional data, but apparently x/y still works
data: data.map((i) => ({x: i.week, y: i.commits})), data: data.map((i) => ({x: i.week, y: i.commits})),
label: 'Commits', label: 'Commits',
backgroundColor: chartJsColors['commits'], backgroundColor: chartJsColors['commits'],
borderWidth: 0, borderWidth: 0,
tension: 0.3, tension: 0.3,
}, } as unknown as ChartDataset<'bar'>,
], ],
}; };
} }
-1
View File
@@ -41,7 +41,6 @@ export async function initCaptcha() {
// * the INPUT_NAME is a "const", it should not be changed. // * the INPUT_NAME is a "const", it should not be changed.
// * the "mCaptcha.default" is actually the "Widget". // * the "mCaptcha.default" is actually the "Widget".
// @ts-expect-error TS2540: Cannot assign to 'INPUT_NAME' because it is a read-only property.
mCaptcha.INPUT_NAME = 'm-captcha-response'; mCaptcha.INPUT_NAME = 'm-captcha-response';
const instanceURL = captchaEl.getAttribute('data-instance-url')!; const instanceURL = captchaEl.getAttribute('data-instance-url')!;
-4
View File
@@ -6,13 +6,9 @@ const {pageData} = window.config;
async function initInputCitationValue(citationCopyApa: HTMLButtonElement, citationCopyBibtex: HTMLButtonElement) { async function initInputCitationValue(citationCopyApa: HTMLButtonElement, citationCopyBibtex: HTMLButtonElement) {
const [{Cite, plugins}] = await Promise.all([ const [{Cite, plugins}] = await Promise.all([
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'), import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'),
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'), import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'),
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'), import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'),
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "citation-js-csl" */'@citation-js/plugin-csl'), import(/* webpackChunkName: "citation-js-csl" */'@citation-js/plugin-csl'),
]); ]);
const {citationFileContent} = pageData; const {citationFileContent} = pageData;
@@ -72,10 +72,9 @@ class Source {
const sourcesByUrl = new Map<string, Source | null>(); const sourcesByUrl = new Map<string, Source | null>();
const sourcesByPort = new Map<MessagePort, Source | null>(); const sourcesByPort = new Map<MessagePort, Source | null>();
// @ts-expect-error: typescript bug? (self as unknown as SharedWorkerGlobalScope).addEventListener('connect', (e: MessageEvent) => {
self.addEventListener('connect', (e: MessageEvent) => {
for (const port of e.ports) { for (const port of e.ports) {
port.addEventListener('message', (event) => { port.addEventListener('message', (event: MessageEvent) => {
if (!self.EventSource) { if (!self.EventSource) {
// some browsers (like PaleMoon, Firefox<53) don't support EventSource in SharedWorkerGlobalScope. // some browsers (like PaleMoon, Firefox<53) don't support EventSource in SharedWorkerGlobalScope.
// this event handler needs EventSource when doing "new Source(url)", so just post a message back to the caller, // this event handler needs EventSource when doing "new Source(url)", so just post a message back to the caller,
+1 -2
View File
@@ -56,8 +56,7 @@ function initRepoDiffConversationForm() {
const idx = newConversationHolder.getAttribute('data-idx'); const idx = newConversationHolder.getAttribute('data-idx');
form.closest('.conversation-holder')!.replaceWith(newConversationHolder); form.closest('.conversation-holder')!.replaceWith(newConversationHolder);
// @ts-expect-error -- prevent further usage of the form because it should have been replaced (form as any) = null; // prevent further usage of the form because it should have been replaced
form = null;
if (trLineType) { if (trLineType) {
// if there is a line-type for the "tr", it means the form is on the diff page // if there is a line-type for the "tr", it means the form is on the diff page
+1 -1
View File
@@ -201,7 +201,7 @@ async function pinMoveEnd(e: SortableEvent) {
} }
async function initIssuePinSort() { async function initIssuePinSort() {
const pinDiv = document.querySelector('#issue-pins'); const pinDiv = document.querySelector<HTMLElement>('#issue-pins');
if (pinDiv === null) return; if (pinDiv === null) return;
+2 -2
View File
@@ -38,7 +38,7 @@ async function moveIssue({item, from, to, oldIndex}: SortableEvent): Promise<voi
async function initRepoProjectSortable(): Promise<void> { async function initRepoProjectSortable(): Promise<void> {
// the HTML layout is: #project-board.board > .project-column .cards > .issue-card // the HTML layout is: #project-board.board > .project-column .cards > .issue-card
const mainBoard = document.querySelector('#project-board')!; const mainBoard = document.querySelector<HTMLElement>('#project-board')!;
let boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column'); let boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column');
createSortable(mainBoard, { createSortable(mainBoard, {
group: 'project-column', group: 'project-column',
@@ -67,7 +67,7 @@ async function initRepoProjectSortable(): Promise<void> {
}); });
for (const boardColumn of boardColumns) { for (const boardColumn of boardColumns) {
const boardCardList = boardColumn.querySelector('.cards')!; const boardCardList = boardColumn.querySelector<HTMLElement>('.cards')!;
createSortable(boardCardList, { createSortable(boardCardList, {
group: 'shared', group: 'shared',
onAdd: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises onAdd: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises
@@ -56,12 +56,11 @@ describe('Repository Branch Settings', () => {
vi.mocked(POST).mockResolvedValue({ok: true} as Response); vi.mocked(POST).mockResolvedValue({ok: true} as Response);
// Mock createSortable to capture and execute the onEnd callback // Mock createSortable to capture and execute the onEnd callback
vi.mocked(createSortable).mockImplementation(async (_el: Element, options: SortableOptions | undefined) => { vi.mocked(createSortable).mockImplementation(async (_el: HTMLElement, options: SortableOptions | undefined) => {
if (options?.onEnd) { if (options?.onEnd) {
options.onEnd(new Event('SortableEvent') as SortableEvent); options.onEnd(new Event('SortableEvent') as SortableEvent);
} }
// @ts-expect-error: mock is incomplete return {destroy: vi.fn()} as unknown as Sortable;
return {destroy: vi.fn()} as Sortable;
}); });
initRepoSettingsBranchesDrag(); initRepoSettingsBranchesDrag();
@@ -4,7 +4,7 @@ import {showErrorToast} from '../modules/toast.ts';
import {queryElemChildren} from '../utils/dom.ts'; import {queryElemChildren} from '../utils/dom.ts';
export function initRepoSettingsBranchesDrag() { export function initRepoSettingsBranchesDrag() {
const protectedBranchesList = document.querySelector('#protected-branches-list'); const protectedBranchesList = document.querySelector<HTMLElement>('#protected-branches-list');
if (!protectedBranchesList) return; if (!protectedBranchesList) return;
createSortable(protectedBranchesList, { createSortable(protectedBranchesList, {
+16 -15
View File
@@ -1,13 +1,11 @@
import {emojiKeys, emojiHTML, emojiString} from './emoji.ts'; import {emojiKeys, emojiHTML, emojiString} from './emoji.ts';
import {html, htmlRaw} from '../utils/html.ts'; import {html, htmlRaw} from '../utils/html.ts';
import type {TributeCollection} from 'tributejs';
type TributeItem = Record<string, any>;
export async function attachTribute(element: HTMLElement) { export async function attachTribute(element: HTMLElement) {
const {default: Tribute} = await import(/* webpackChunkName: "tribute" */'tributejs'); const {default: Tribute} = await import(/* webpackChunkName: "tribute" */'tributejs');
const collections = [ const emojiCollection: TributeCollection<string> = { // emojis
{ // emojis
trigger: ':', trigger: ':',
requireLeadingSpace: true, requireLeadingSpace: true,
values: (query: string, cb: (matches: Array<string>) => void) => { values: (query: string, cb: (matches: Array<string>) => void) => {
@@ -20,18 +18,20 @@ export async function attachTribute(element: HTMLElement) {
} }
cb(matches); cb(matches);
}, },
lookup: (item: TributeItem) => item, lookup: (item) => item,
selectTemplate: (item: TributeItem) => { selectTemplate: (item) => {
if (item === undefined) return null; if (item === undefined) return '';
return emojiString(item.original); return emojiString(item.original) ?? '';
}, },
menuItemTemplate: (item: TributeItem) => { menuItemTemplate: (item) => {
return html`<div class="tribute-item">${htmlRaw(emojiHTML(item.original))}<span>${item.original}</span></div>`; return html`<div class="tribute-item">${htmlRaw(emojiHTML(item.original))}<span>${item.original}</span></div>`;
}, },
}, { // mentions };
const mentionCollection: TributeCollection<Record<string, any>> = {
values: window.config.mentionValues, values: window.config.mentionValues,
requireLeadingSpace: true, requireLeadingSpace: true,
menuItemTemplate: (item: TributeItem) => { menuItemTemplate: (item) => {
const fullNameHtml = item.original.fullname && item.original.fullname !== '' ? html`<span class="fullname">${item.original.fullname}</span>` : ''; const fullNameHtml = item.original.fullname && item.original.fullname !== '' ? html`<span class="fullname">${item.original.fullname}</span>` : '';
return html` return html`
<div class="tribute-item"> <div class="tribute-item">
@@ -41,11 +41,12 @@ export async function attachTribute(element: HTMLElement) {
</div> </div>
`; `;
}, },
}, };
];
// @ts-expect-error TS2351: This expression is not constructable (strange, why) const tribute = new Tribute({
const tribute = new Tribute({collection: collections, noMatchTemplate: ''}); collection: [emojiCollection as TributeCollection<any>, mentionCollection],
noMatchTemplate: () => '',
});
tribute.attach(element); tribute.attach(element);
return tribute; return tribute;
} }
-30
View File
@@ -1,33 +1,3 @@
declare module '*.svg' {
const value: string;
export default value;
}
declare module '*.css' {
const value: string;
export default value;
}
declare module '*.vue' {
import type {DefineComponent} from 'vue';
const component: DefineComponent<unknown, unknown, any>;
export default component;
// Here we declare all exports from vue files so `tsc` or `tsgo` can work for
// non-vue files. To lint .vue files, `vue-tsc` must be used.
export function initDashboardRepoList(): void;
export function initRepositoryActionView(): void;
}
declare module 'htmx.org/dist/htmx.esm.js' {
const value = await import('htmx.org');
export default value;
}
declare module 'swagger-ui-dist/swagger-ui-es-bundle.js' {
const value = await import('swagger-ui-dist');
export default value.SwaggerUIBundle;
}
interface JQuery { interface JQuery {
areYouSure: any, // jquery.are-you-sure areYouSure: any, // jquery.are-you-sure
fomanticExt: any; // fomantic extension fomanticExt: any; // fomantic extension
+1 -2
View File
@@ -3,12 +3,11 @@ import {queryElems} from '../utils/dom.ts';
export async function initMarkupRenderAsciicast(elMarkup: HTMLElement): Promise<void> { export async function initMarkupRenderAsciicast(elMarkup: HTMLElement): Promise<void> {
queryElems(elMarkup, '.asciinema-player-container', async (el) => { queryElems(elMarkup, '.asciinema-player-container', async (el) => {
const [player] = await Promise.all([ const [player] = await Promise.all([
// @ts-expect-error: module exports no types
import(/* webpackChunkName: "asciinema-player" */'asciinema-player'), import(/* webpackChunkName: "asciinema-player" */'asciinema-player'),
import(/* webpackChunkName: "asciinema-player" */'asciinema-player/dist/bundle/asciinema-player.css'), import(/* webpackChunkName: "asciinema-player" */'asciinema-player/dist/bundle/asciinema-player.css'),
]); ]);
player.create(el.getAttribute('data-asciinema-player-src'), el, { player.create(el.getAttribute('data-asciinema-player-src')!, el, {
// poster (a preview frame) to display until the playback is started. // poster (a preview frame) to display until the playback is started.
// Set it to 1 hour (also means the end if the video is shorter) to make the preview frame show more. // Set it to 1 hour (also means the end if the video is shorter) to make the preview frame show more.
poster: 'npt:1:0:0', poster: 'npt:1:0:0',
+3 -3
View File
@@ -1,9 +1,9 @@
import type {SortableOptions, SortableEvent} from 'sortablejs'; import type {SortableOptions, SortableEvent} from 'sortablejs';
import type SortableType from 'sortablejs'; import type SortableType from 'sortablejs';
export async function createSortable(el: Element, opts: {handle?: string} & SortableOptions = {}): Promise<SortableType> { export async function createSortable(el: HTMLElement, opts: {handle?: string} & SortableOptions = {}): Promise<SortableType> {
// @ts-expect-error: wrong type derived by typescript // type reassigned because typescript derives the wrong type from this import
const {Sortable} = await import(/* webpackChunkName: "sortablejs" */'sortablejs'); const {Sortable} = (await import(/* webpackChunkName: "sortablejs" */'sortablejs') as unknown as {Sortable: typeof SortableType});
return new Sortable(el, { return new Sortable(el, {
animation: 150, animation: 150,
+2 -3
View File
@@ -4,17 +4,16 @@ try {
new Intl.NumberFormat('en', {style: 'unit', unit: 'minute'}).format(1); new Intl.NumberFormat('en', {style: 'unit', unit: 'minute'}).format(1);
} catch { } catch {
const intlNumberFormat = Intl.NumberFormat; const intlNumberFormat = Intl.NumberFormat;
// @ts-expect-error - polyfill is incomplete
Intl.NumberFormat = function(locales: string | string[], options: Intl.NumberFormatOptions) { Intl.NumberFormat = function(locales: string | string[], options: Intl.NumberFormatOptions) {
if (options.style === 'unit') { if (options.style === 'unit') {
return { return {
format(value: number | bigint | string) { format(value: number | bigint | string) {
return ` ${value} ${options.unit}`; return ` ${value} ${options.unit}`;
}, },
}; } as Intl.NumberFormat;
} }
return intlNumberFormat(locales, options); return intlNumberFormat(locales, options);
}; } as unknown as typeof Intl.NumberFormat;
} }
export function weakRefClass() { export function weakRefClass() {