1
1
mirror of https://github.com/go-gitea/gitea synced 2025-12-07 05:18:29 +00:00

Enable TypeScript strictNullChecks (#35843)

A big step towards enabling strict mode in Typescript.

There was definitely a good share of potential bugs while refactoring
this. When in doubt, I opted to keep the potentially broken behaviour.
Notably, the `DOMEvent` type is gone, it was broken and we're better of
with type assertions on `e.target`.

---------

Signed-off-by: silverwind <me@silverwind.io>
Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
silverwind
2025-12-03 03:13:16 +01:00
committed by GitHub
parent 9f268edd2f
commit 46d7adefe0
108 changed files with 686 additions and 658 deletions

View File

@@ -5,7 +5,7 @@ import {onMounted, shallowRef} from 'vue';
import type {Value as HeatmapValue, Locale as HeatmapLocale} from '@silverwind/vue3-calendar-heatmap';
defineProps<{
values?: HeatmapValue[];
values: HeatmapValue[];
locale: {
textTotalContributions: string;
heatMapLocale: Partial<HeatmapLocale>;
@@ -28,7 +28,7 @@ const endDate = shallowRef(new Date());
onMounted(() => {
// work around issue with first legend color being rendered twice and legend cut off
const legend = document.querySelector<HTMLElement>('.vch__external-legend-wrapper');
const legend = document.querySelector<HTMLElement>('.vch__external-legend-wrapper')!;
legend.setAttribute('viewBox', '12 0 80 10');
legend.style.marginRight = '-12px';
});

View File

@@ -11,15 +11,17 @@ const props = defineProps<{
}>();
const loading = shallowRef(false);
const issue = shallowRef<Issue>(null);
const issue = shallowRef<Issue | null>(null);
const renderedLabels = shallowRef('');
const errorMessage = shallowRef('');
const createdAt = computed(() => {
if (!issue?.value) return '';
return new Date(issue.value.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});
});
const body = computed(() => {
if (!issue?.value) return '';
const body = issue.value.body.replace(/\n+/g, ' ');
return body.length > 85 ? `${body.substring(0, 85)}` : body;
});

View File

@@ -110,9 +110,9 @@ export default defineComponent({
},
mounted() {
const el = document.querySelector('#dashboard-repo-list');
const el = document.querySelector('#dashboard-repo-list')!;
this.changeReposFilter(this.reposFilter);
fomanticQuery(el.querySelector('.ui.dropdown')).dropdown();
fomanticQuery(el.querySelector('.ui.dropdown')!).dropdown();
this.textArchivedFilterTitles = {
'archived': this.textShowOnlyArchived,

View File

@@ -23,7 +23,7 @@ type CommitListResult = {
export default defineComponent({
components: {SvgIcon},
data: () => {
const el = document.querySelector('#diff-commit-select');
const el = document.querySelector('#diff-commit-select')!;
return {
menuVisible: false,
isLoading: false,
@@ -35,7 +35,7 @@ export default defineComponent({
mergeBase: el.getAttribute('data-merge-base'),
commits: [] as Array<Commit>,
hoverActivated: false,
lastReviewCommitSha: '',
lastReviewCommitSha: '' as string | null,
uniqueIdMenu: generateElemId('diff-commit-selector-menu-'),
uniqueIdShowAll: generateElemId('diff-commit-selector-show-all-'),
};
@@ -165,7 +165,7 @@ export default defineComponent({
},
/** Called when user clicks on since last review */
changesSinceLastReviewClick() {
window.location.assign(`${this.issueLink}/files/${this.lastReviewCommitSha}..${this.commits.at(-1).id}${this.queryParams}`);
window.location.assign(`${this.issueLink}/files/${this.lastReviewCommitSha}..${this.commits.at(-1)!.id}${this.queryParams}`);
},
/** Clicking on a single commit opens this specific commit */
commitClicked(commitId: string, newWindow = false) {
@@ -193,7 +193,7 @@ export default defineComponent({
// find all selected commits and generate a link
const firstSelected = this.commits.findIndex((x) => x.selected);
const lastSelected = this.commits.findLastIndex((x) => x.selected);
let beforeCommitID: string;
let beforeCommitID: string | null = null;
if (firstSelected === 0) {
beforeCommitID = this.mergeBase;
} else {
@@ -204,7 +204,7 @@ export default defineComponent({
if (firstSelected === lastSelected) {
// if the start and end are the same, we show this single commit
window.location.assign(`${this.issueLink}/commits/${afterCommitID}${this.queryParams}`);
} else if (beforeCommitID === this.mergeBase && afterCommitID === this.commits.at(-1).id) {
} else if (beforeCommitID === this.mergeBase && afterCommitID === this.commits.at(-1)!.id) {
// if the first commit is selected and the last commit is selected, we show all commits
window.location.assign(`${this.issueLink}/files${this.queryParams}`);
} else {

View File

@@ -12,14 +12,14 @@ const store = diffTreeStore();
onMounted(() => {
// Default to true if unset
store.fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) !== 'false';
document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', toggleVisibility);
document.querySelector('.diff-toggle-file-tree-button')!.addEventListener('click', toggleVisibility);
hashChangeListener();
window.addEventListener('hashchange', hashChangeListener);
});
onUnmounted(() => {
document.querySelector('.diff-toggle-file-tree-button').removeEventListener('click', toggleVisibility);
document.querySelector('.diff-toggle-file-tree-button')!.removeEventListener('click', toggleVisibility);
window.removeEventListener('hashchange', hashChangeListener);
});
@@ -33,7 +33,7 @@ function expandSelectedFile() {
if (store.selectedItem) {
const box = document.querySelector(store.selectedItem);
const folded = box?.getAttribute('data-folded') === 'true';
if (folded) setFileFolding(box, box.querySelector('.fold-file'), false);
if (folded) setFileFolding(box, box.querySelector('.fold-file')!, false);
}
}
@@ -48,10 +48,10 @@ function updateVisibility(visible: boolean) {
}
function updateState(visible: boolean) {
const btn = document.querySelector('.diff-toggle-file-tree-button');
const btn = document.querySelector('.diff-toggle-file-tree-button')!;
const [toShow, toHide] = btn.querySelectorAll('.icon');
const tree = document.querySelector('#diff-file-tree');
const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text');
const tree = document.querySelector('#diff-file-tree')!;
const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text')!;
btn.setAttribute('data-tooltip-content', newTooltip);
toggleElem(tree, visible);
toggleElem(toShow, !visible);

View File

@@ -402,7 +402,7 @@ export default defineComponent({
}
// auto-scroll to the last log line of the last step
let autoScrollJobStepElement: HTMLElement;
let autoScrollJobStepElement: HTMLElement | undefined;
for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) {
if (!autoScrollStepIndexes.get(stepIndex)) continue;
autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex);
@@ -468,7 +468,7 @@ export default defineComponent({
}
const logLine = this.elStepsContainer().querySelector(selectedLogStep);
if (!logLine) return;
logLine.querySelector<HTMLAnchorElement>('.line-num').click();
logLine.querySelector<HTMLAnchorElement>('.line-num')!.click();
},
},
});

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup>
// @ts-expect-error - module exports no types
import {VueBarGraph} from 'vue-bar-graph';
import {computed, onMounted, shallowRef, useTemplateRef} from 'vue';
import {computed, onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue';
const colors = shallowRef({
barColor: 'green',
@@ -41,8 +41,8 @@ const graphWidth = computed(() => {
return activityTopAuthors.length * 40;
});
const styleElement = useTemplateRef('styleElement');
const altStyleElement = useTemplateRef('altStyleElement');
const styleElement = useTemplateRef('styleElement') as Readonly<ShallowRef<HTMLDivElement>>;
const altStyleElement = useTemplateRef('altStyleElement') as Readonly<ShallowRef<HTMLDivElement>>;
onMounted(() => {
const refStyle = window.getComputedStyle(styleElement.value);

View File

@@ -20,7 +20,10 @@ type TabLoadingStates = Record<SelectedTab, '' | 'loading' | 'done'>
export default defineComponent({
components: {SvgIcon},
props: {
elRoot: HTMLElement,
elRoot: {
type: HTMLElement,
required: true,
},
},
data() {
const shouldShowTabBranches = this.elRoot.getAttribute('data-show-tab-branches') === 'true';
@@ -33,28 +36,28 @@ export default defineComponent({
activeItemIndex: 0,
tabLoadingStates: {} as TabLoadingStates,
textReleaseCompare: this.elRoot.getAttribute('data-text-release-compare'),
textBranches: this.elRoot.getAttribute('data-text-branches'),
textTags: this.elRoot.getAttribute('data-text-tags'),
textFilterBranch: this.elRoot.getAttribute('data-text-filter-branch'),
textFilterTag: this.elRoot.getAttribute('data-text-filter-tag'),
textDefaultBranchLabel: this.elRoot.getAttribute('data-text-default-branch-label'),
textCreateTag: this.elRoot.getAttribute('data-text-create-tag'),
textCreateBranch: this.elRoot.getAttribute('data-text-create-branch'),
textCreateRefFrom: this.elRoot.getAttribute('data-text-create-ref-from'),
textNoResults: this.elRoot.getAttribute('data-text-no-results'),
textViewAllBranches: this.elRoot.getAttribute('data-text-view-all-branches'),
textViewAllTags: this.elRoot.getAttribute('data-text-view-all-tags'),
textReleaseCompare: this.elRoot.getAttribute('data-text-release-compare')!,
textBranches: this.elRoot.getAttribute('data-text-branches')!,
textTags: this.elRoot.getAttribute('data-text-tags')!,
textFilterBranch: this.elRoot.getAttribute('data-text-filter-branch')!,
textFilterTag: this.elRoot.getAttribute('data-text-filter-tag')!,
textDefaultBranchLabel: this.elRoot.getAttribute('data-text-default-branch-label')!,
textCreateTag: this.elRoot.getAttribute('data-text-create-tag')!,
textCreateBranch: this.elRoot.getAttribute('data-text-create-branch')!,
textCreateRefFrom: this.elRoot.getAttribute('data-text-create-ref-from')!,
textNoResults: this.elRoot.getAttribute('data-text-no-results')!,
textViewAllBranches: this.elRoot.getAttribute('data-text-view-all-branches')!,
textViewAllTags: this.elRoot.getAttribute('data-text-view-all-tags')!,
currentRepoDefaultBranch: this.elRoot.getAttribute('data-current-repo-default-branch'),
currentRepoLink: this.elRoot.getAttribute('data-current-repo-link'),
currentTreePath: this.elRoot.getAttribute('data-current-tree-path'),
currentRepoDefaultBranch: this.elRoot.getAttribute('data-current-repo-default-branch')!,
currentRepoLink: this.elRoot.getAttribute('data-current-repo-link')!,
currentTreePath: this.elRoot.getAttribute('data-current-tree-path')!,
currentRefType: this.elRoot.getAttribute('data-current-ref-type') as GitRefType,
currentRefShortName: this.elRoot.getAttribute('data-current-ref-short-name'),
currentRefShortName: this.elRoot.getAttribute('data-current-ref-short-name')!,
refLinkTemplate: this.elRoot.getAttribute('data-ref-link-template'),
refFormActionTemplate: this.elRoot.getAttribute('data-ref-form-action-template'),
dropdownFixedText: this.elRoot.getAttribute('data-dropdown-fixed-text'),
refLinkTemplate: this.elRoot.getAttribute('data-ref-link-template')!,
refFormActionTemplate: this.elRoot.getAttribute('data-ref-form-action-template')!,
dropdownFixedText: this.elRoot.getAttribute('data-dropdown-fixed-text')!,
showTabBranches: shouldShowTabBranches,
showTabTags: this.elRoot.getAttribute('data-show-tab-tags') === 'true',
allowCreateNewRef: this.elRoot.getAttribute('data-allow-create-new-ref') === 'true',
@@ -92,7 +95,7 @@ export default defineComponent({
}).length;
},
createNewRefFormActionUrl() {
return `${this.currentRepoLink}/branches/_new/${this.currentRefType}/${pathEscapeSegments(this.currentRefShortName)}`;
return `${this.currentRepoLink}/branches/_new/${this.currentRefType}/${pathEscapeSegments(this.currentRefShortName!)}`;
},
},
watch: {

View File

@@ -174,7 +174,7 @@ export default defineComponent({
user.max_contribution_type = 0;
const filteredWeeks = user.weeks.filter((week: Record<string, number>) => {
const oneWeek = 7 * 24 * 60 * 60 * 1000;
if (week.week >= this.xAxisMin - oneWeek && week.week <= this.xAxisMax + oneWeek) {
if (week.week >= this.xAxisMin! - oneWeek && week.week <= this.xAxisMax! + oneWeek) {
user.total_commits += week.commits;
user.total_additions += week.additions;
user.total_deletions += week.deletions;
@@ -238,8 +238,8 @@ export default defineComponent({
},
updateOtherCharts({chart}: {chart: Chart}, reset: boolean = false) {
const minVal = Number(chart.options.scales.x.min);
const maxVal = Number(chart.options.scales.x.max);
const minVal = Number(chart.options.scales?.x?.min);
const maxVal = Number(chart.options.scales?.x?.max);
if (reset) {
this.xAxisMin = this.xAxisStart;
this.xAxisMax = this.xAxisEnd;
@@ -302,8 +302,8 @@ export default defineComponent({
},
scales: {
x: {
min: this.xAxisMin,
max: this.xAxisMax,
min: this.xAxisMin ?? undefined,
max: this.xAxisMax ?? undefined,
type: 'time',
grid: {
display: false,
@@ -334,7 +334,7 @@ export default defineComponent({
<div class="ui header tw-flex tw-items-center tw-justify-between">
<div>
<relative-time
v-if="xAxisMin > 0"
v-if="xAxisMin && xAxisMin > 0"
format="datetime"
year="numeric"
month="short"
@@ -346,7 +346,7 @@ export default defineComponent({
</relative-time>
{{ isLoading ? locale.loadingTitle : errorText ? locale.loadingTitleFailed: "-" }}
<relative-time
v-if="xAxisMax > 0"
v-if="xAxisMax && xAxisMax > 0"
format="datetime"
year="numeric"
month="short"

View File

@@ -1,10 +1,10 @@
<script lang="ts" setup>
import { ref, computed, watch, nextTick, useTemplateRef, onMounted, onUnmounted } from 'vue';
import {ref, computed, watch, nextTick, useTemplateRef, onMounted, onUnmounted, type ShallowRef} from 'vue';
import {generateElemId} from '../utils/dom.ts';
import { GET } from '../modules/fetch.ts';
import { filterRepoFilesWeighted } from '../features/repo-findfile.ts';
import { pathEscapeSegments } from '../utils/url.ts';
import { SvgIcon } from '../svg.ts';
import {GET} from '../modules/fetch.ts';
import {filterRepoFilesWeighted} from '../features/repo-findfile.ts';
import {pathEscapeSegments} from '../utils/url.ts';
import {SvgIcon} from '../svg.ts';
import {throttle} from 'throttle-debounce';
const props = defineProps({
@@ -15,8 +15,8 @@ const props = defineProps({
placeholder: { type: String, required: true },
});
const refElemInput = useTemplateRef<HTMLInputElement>('searchInput');
const refElemPopup = useTemplateRef<HTMLElement>('searchPopup');
const refElemInput = useTemplateRef('searchInput') as Readonly<ShallowRef<HTMLInputElement>>;
const refElemPopup = useTemplateRef('searchPopup') as Readonly<ShallowRef<HTMLDivElement>>;
const searchQuery = ref('');
const allFiles = ref<string[]>([]);

View File

@@ -1,9 +1,9 @@
<script lang="ts" setup>
import ViewFileTreeItem from './ViewFileTreeItem.vue';
import {onMounted, useTemplateRef} from 'vue';
import {onMounted, useTemplateRef, type ShallowRef} from 'vue';
import {createViewFileTreeStore} from './ViewFileTreeStore.ts';
const elRoot = useTemplateRef('elRoot');
const elRoot = useTemplateRef('elRoot') as Readonly<ShallowRef<HTMLDivElement>>;;
const props = defineProps({
repoLink: {type: String, required: true},
@@ -24,7 +24,7 @@ onMounted(async () => {
<template>
<div class="view-file-tree-items" ref="elRoot">
<ViewFileTreeItem v-for="item in store.rootFiles" :key="item.name" :item="item" :store="store"/>
<ViewFileTreeItem v-for="item in store.rootFiles" :key="item.entryName" :item="item" :store="store"/>
</div>
</template>

View File

@@ -4,7 +4,7 @@ import {isPlainClick} from '../utils/dom.ts';
import {shallowRef} from 'vue';
import {type createViewFileTreeStore} from './ViewFileTreeStore.ts';
type Item = {
export type Item = {
entryName: string;
entryMode: 'blob' | 'exec' | 'tree' | 'commit' | 'symlink' | 'unknown';
entryIcon: string;

View File

@@ -3,10 +3,11 @@ import {GET} from '../modules/fetch.ts';
import {pathEscapeSegments} from '../utils/url.ts';
import {createElementFromHTML} from '../utils/dom.ts';
import {html} from '../utils/html.ts';
import type {Item} from './ViewFileTreeItem.vue';
export function createViewFileTreeStore(props: {repoLink: string, treePath: string, currentRefNameSubURL: string}) {
const store = reactive({
rootFiles: [],
rootFiles: [] as Array<Item>,
selectedItem: props.treePath,
async loadChildren(treePath: string, subPath: string = '') {
@@ -28,7 +29,7 @@ export function createViewFileTreeStore(props: {repoLink: string, treePath: stri
const u = new URL(url, window.origin);
u.searchParams.set('only_content', 'true');
const response = await GET(u.href);
const elViewContent = document.querySelector('.repo-view-content');
const elViewContent = document.querySelector('.repo-view-content')!;
elViewContent.innerHTML = await response.text();
const elViewContentData = elViewContent.querySelector('.repo-view-content-data');
if (!elViewContentData) return; // if error occurs, there is no such element
@@ -39,7 +40,7 @@ export function createViewFileTreeStore(props: {repoLink: string, treePath: stri
async navigateTreeView(treePath: string) {
const url = store.buildTreePathWebUrl(treePath);
window.history.pushState({treePath, url}, null, url);
window.history.pushState({treePath, url}, '', url);
store.selectedItem = treePath;
await store.loadViewContent(url);
},