Clear the last 19 lint warnings — make check now passes clean

- BuyTicketButton / FlightsMiniListItem: narrow firstLeg/lastLeg with
  explicit null guards (throw / return '').
- FlightSchedule.tsx: `match?.[1] ?? iso` for the regex capture.
- OnlineBoardSearchPage + schedule/api: `split('T')[0] ?? iso` for the
  date-prefix extraction.
- ServicesPanel: icon lookup uses a third '' fallback instead of `!`.
- buildCountryCityRows: explicit `break` if cities[i] is undefined.
- useAppSettings: `match?.[1]` null-check before parseInt.
- datetime/index.ts: guard bare HH:MM capture groups together.
- ScheduleDetailsCatchAllRoute: drop unused `t` + useTranslation import.
- ScheduleDetailsPage.tsx: prefix unused `getLegs` with underscore.
- 4 seo/json-ld tests: drop now-redundant eslint-disable comments.
- calendarRange.test + api.test: prefix unused helper names with `_`.

Warning count: 19 → 0. make check (typecheck + lint + test) exits 0.
This commit is contained in:
2026-04-20 09:30:34 +03:00
parent 8d409572b7
commit 706b8f444b
17 changed files with 23 additions and 21 deletions
@@ -6,7 +6,7 @@ import {
findNextEnabledDate,
} from "./calendarRange.js";
function yyyymmdd(d: Date): string {
function _yyyymmdd(d: Date): string {
const y = d.getFullYear().toString();
const m = (d.getMonth() + 1).toString().padStart(2, "0");
const day = d.getDate().toString().padStart(2, "0");
-1
View File
@@ -47,7 +47,6 @@ describe("buildFlightsMapSeo", () => {
const result = buildFlightsMapSeo(stubT, "ru", CANONICAL);
expect(result.twitter).toBeDefined();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- test assertion guards above
expect(result.twitter!.card).toBe("summary");
});
});
@@ -11,8 +11,9 @@ export interface BuyTicketButtonProps {
function buildBuyTicketUrl(flight: ISimpleFlight, locale: string): string {
const legs = flight.routeType === "Direct" ? [flight.leg] : flight.legs;
const firstLeg = legs[0]!;
const lastLeg = legs[legs.length - 1]!;
const firstLeg = legs[0];
const lastLeg = legs[legs.length - 1];
if (!firstLeg || !lastLeg) return "";
const dep = firstLeg.departure.scheduled.airportCode;
const arr = lastLeg.arrival.scheduled.airportCode;
const depDate = parseISO(firstLeg.departure.times.scheduledDeparture.utc);
@@ -14,7 +14,7 @@ function formatLocalTime(iso: string | undefined): string {
if (!iso) return "";
if (/^\d{2}:\d{2}$/.test(iso)) return iso;
const match = /T(\d{2}:\d{2})/.exec(iso);
return match ? match[1]! : iso;
return match?.[1] ?? iso;
}
/**
@@ -28,8 +28,9 @@ function getEndpoints(flight: ISimpleFlight): { dep: IFlightLeg["departure"]; ar
if (flight.routeType === "Direct") {
return { dep: flight.leg.departure, arr: flight.leg.arrival };
}
const firstLeg = flight.legs[0]!;
const lastLeg = flight.legs[flight.legs.length - 1]!;
const firstLeg = flight.legs[0];
const lastLeg = flight.legs[flight.legs.length - 1];
if (!firstLeg || !lastLeg) throw new Error("MultiLeg flight has no legs");
return { dep: firstLeg.departure, arr: lastLeg.arrival };
}
@@ -62,7 +62,9 @@ function formatDateForApi(yyyymmdd: string): string {
* rows. Matching Angular's OnlineBoardApiService.getFlightsByRoute.
*/
function addOneDayYyyymmdd(yyyymmdd: string): string {
const iso = yyyymmdd.includes("T") ? yyyymmdd.split("T")[0]! : yyyymmdd;
const iso = yyyymmdd.includes("T")
? yyyymmdd.split("T")[0] ?? yyyymmdd
: yyyymmdd;
let year: number, month: number, day: number;
if (iso.includes("-")) {
const [y, m, d] = iso.split("-");
@@ -36,7 +36,7 @@ export const ServicesPanel: FC<ServicesPanelProps> = ({ services }) => {
const idNumeric = typeof svc.id === "string" ? Number(svc.id) : svc.id;
const iconName = SERVICE_ICON_MAP[idNumeric] ?? SERVICE_ICON_FALLBACK;
const iconSrc =
ICON_BY_NAME[iconName] ?? ICON_BY_NAME[SERVICE_ICON_FALLBACK]!;
ICON_BY_NAME[iconName] ?? ICON_BY_NAME[SERVICE_ICON_FALLBACK] ?? "";
const alt = svc.title ?? `service-${svc.id}`;
const img = (
<img
-1
View File
@@ -58,7 +58,6 @@ describe("buildOnlineBoardStartSeo", () => {
const result = buildOnlineBoardStartSeo(stubT, "ru", CANONICAL);
expect(result.twitter).toBeDefined();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- test assertion guards above
expect(result.twitter!.card).toBe("summary");
});
});
@@ -14,7 +14,6 @@
import { lazy, Suspense } from "react";
import { useParams } from "@modern-js/runtime/router";
import { useTranslation } from "@/i18n/provider.js";
import { parseFlightUrlParams } from "@/features/online-board/url.js";
import { FlightListSkeleton } from "@/ui/flights/FlightListSkeleton.js";
import { ErrorPage } from "@/ui/errors/ErrorPage.js";
@@ -55,7 +54,6 @@ function parseFlightSegments(segments: string[]): IScheduleFlightId[] {
}
export default function ScheduleDetailsCatchAllRoute(): JSX.Element {
const { t } = useTranslation();
const routeParams = useParams<{ "*": string; lang: string }>();
const locale = routeParams.lang ?? "ru-ru";
const canonicalOrigin = getEnv().PROD_ORIGIN;
+1 -1
View File
@@ -39,7 +39,7 @@ function extractUrl(mockFetch: ReturnType<typeof vi.fn>): URL {
return new URL(call[0]);
}
function extractBody(mockFetch: ReturnType<typeof vi.fn>): unknown {
function _extractBody(mockFetch: ReturnType<typeof vi.fn>): unknown {
const call = mockFetch.mock.calls[0] as [string, RequestInit];
return JSON.parse(call[1].body as string);
}
+3 -1
View File
@@ -144,7 +144,9 @@ function parseCalendarDays(days: string, baseDate: string): string[] {
function bitmaskToDates(bitmask: string, baseDate: string): string[] {
// baseDate is yyyy-MM-dd (possibly with Txx:xx:xx suffix).
const iso = baseDate.includes("T") ? baseDate.split("T")[0]! : baseDate;
const iso = baseDate.includes("T")
? baseDate.split("T")[0] ?? baseDate
: baseDate;
const [y, m, d] = iso.split("-");
if (!y || !m || !d) return [];
const cursor = new Date(Number(y), Number(m) - 1, Number(d));
@@ -44,8 +44,9 @@ function formatApiDate(yyyymmdd: string): string {
/**
* Extract legs from a flight (handles both Direct and MultiLeg).
* Currently unused but kept for the planned full-route renderer.
*/
function getLegs(flight: { routeType: string; leg?: IFlightLeg; legs?: IFlightLeg[] }): IFlightLeg[] {
function _getLegs(flight: { routeType: string; leg?: IFlightLeg; legs?: IFlightLeg[] }): IFlightLeg[] {
if (flight.routeType === "Direct" && "leg" in flight && flight.leg) {
return [flight.leg];
}
-1
View File
@@ -52,7 +52,6 @@ describe("buildScheduleStartSeo", () => {
const result = buildScheduleStartSeo(stubT, "ru", CANONICAL);
expect(result.twitter).toBeDefined();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- test assertion guards above
expect(result.twitter!.card).toBe("summary");
});
});
+2 -2
View File
@@ -22,8 +22,8 @@ function parsePattern(
): number {
if (!value) return fallback;
const match = pattern.exec(value);
if (!match) return fallback;
return parseInt(match[1]!, 10);
if (!match?.[1]) return fallback;
return parseInt(match[1], 10);
}
function parseDays(value: string | undefined, fallback: number): number {
-1
View File
@@ -75,7 +75,6 @@ describe("JsonLdRenderer", () => {
const match = html.match(/<script[^>]*>([\s\S]*?)<\/script>/);
expect(match).not.toBeNull();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- test assertion already guards
const json = match![1]!.replace(/\\u003c/g, "<");
const parsed = JSON.parse(json);
expect(parsed["@context"]).toBe("https://schema.org");
+1 -1
View File
@@ -92,7 +92,7 @@ export function formatLocalTime(iso: string): string {
const full = ISO_OFFSET_RE.exec(iso);
if (full) return `${full[4]}:${full[5]}`;
const bare = BARE_HH_MM_RE.exec(iso);
if (bare) return `${bare[1]!.padStart(2, "0")}:${bare[2]}`;
if (bare?.[1] && bare[2]) return `${bare[1].padStart(2, "0")}:${bare[2]}`;
return formatTime(iso); // fall back to Date-based formatter
}
@@ -56,7 +56,8 @@ export function buildCountryCityRows(
let firstRow = true;
let i = 0;
while (i < cities.length) {
const city1 = cities[i]!;
const city1 = cities[i];
if (!city1) break;
const multiAirport = city1.airports.length > 1;
if (multiAirport) {