fix: resolve all 1008 svelte-check type errors across codebase
CI / update (push) Successful in 1m54s

Add type annotations, JSDoc types, null checks, and proper generics
to eliminate all svelte-check errors. Key changes include:
- Type $state(null) variables to avoid 'never' inference
- Add JSDoc typedefs for plain <script> components
- Fix mongoose model typing with Model<any> to avoid union complexity
- Add App.Error/App.PageState interfaces in app.d.ts
- Fix tuple types to array types in types.ts
- Type catch block errors and API handler params
- Add null safety for DOM queries and optional chaining
- Add standard line-clamp property alongside -webkit- prefix
This commit is contained in:
2026-03-02 08:40:15 +01:00
parent 9e5fef1463
commit 4a931c7e30
125 changed files with 871 additions and 600 deletions
@@ -23,7 +23,7 @@ export const POST: RequestHandler = async ({request, cookies, locals}) => {
// Invalidate recipe caches after successful creation
await invalidateRecipeCaches();
} catch(e){
throw error(400, e)
throw error(400, e instanceof Error ? e.message : String(e))
}
return new Response(JSON.stringify({msg: "Added recipe successfully"}),{
status: 200,
@@ -34,7 +34,7 @@ export const POST: RequestHandler = async ({request, locals}) => {
for (const depRecipe of referencingRecipes) {
// Expand ingredient references
if (depRecipe.ingredients) {
depRecipe.ingredients = depRecipe.ingredients.flatMap((item: any) => {
(depRecipe as any).ingredients = depRecipe.ingredients.flatMap((item: any) => {
if (item.type === 'reference' && item.baseRecipeRef && item.baseRecipeRef.equals(recipe._id)) {
if (item.includeIngredients && recipe.ingredients) {
return recipe.ingredients.filter((i: any) => i.type === 'section' || !i.type);
@@ -47,7 +47,7 @@ export const POST: RequestHandler = async ({request, locals}) => {
// Expand instruction references
if (depRecipe.instructions) {
depRecipe.instructions = depRecipe.instructions.flatMap((item: any) => {
(depRecipe as any).instructions = depRecipe.instructions.flatMap((item: any) => {
if (item.type === 'reference' && item.baseRecipeRef && item.baseRecipeRef.equals(recipe._id)) {
if (item.includeInstructions && recipe.instructions) {
return recipe.instructions.filter((i: any) => i.type === 'section' || !i.type);
@@ -24,31 +24,33 @@ export const GET: RequestHandler = async ({ params, locals }) => {
return json([]);
}
const { approvalFilter } = briefQueryConfig(params.recipeLang);
const en = isEnglish(params.recipeLang);
const { approvalFilter } = briefQueryConfig(params.recipeLang!);
const en = isEnglish(params.recipeLang!);
let recipes = await Recipe.find({
_id: { $in: userFavorites.favorites },
...approvalFilter
}).lean() as RecipeModelType[];
}).lean() as unknown as RecipeModelType[];
if (en) {
const englishRecipes = recipes.map(recipe => ({
const englishRecipes = recipes.map(recipe => {
const t = recipe.translations?.en;
return {
_id: recipe._id,
short_name: recipe.translations.en.short_name,
name: recipe.translations.en.name,
category: recipe.translations.en.category,
short_name: t?.short_name,
name: t?.name,
category: t?.category,
icon: recipe.icon,
dateCreated: recipe.dateCreated,
dateModified: recipe.dateModified,
images: recipe.images?.map((img, idx) => ({
mediapath: img.mediapath,
alt: recipe.translations.en.images?.[idx]?.alt || img.alt,
caption: recipe.translations.en.images?.[idx]?.caption || img.caption,
alt: t?.images?.[idx]?.alt || img.alt,
caption: t?.images?.[idx]?.caption || img.caption,
})),
description: recipe.translations.en.description,
note: recipe.translations.en.note,
tags: recipe.translations.en.tags || [],
description: t?.description,
note: t?.note,
tags: t?.tags || [],
season: recipe.season,
baking: recipe.baking,
preparation: recipe.preparation,
@@ -56,13 +58,13 @@ export const GET: RequestHandler = async ({ params, locals }) => {
portions: recipe.portions,
cooking: recipe.cooking,
total_time: recipe.total_time,
ingredients: recipe.translations.en.ingredients || [],
instructions: recipe.translations.en.instructions || [],
preamble: recipe.translations.en.preamble,
addendum: recipe.translations.en.addendum,
ingredients: t?.ingredients || [],
instructions: t?.instructions || [],
preamble: t?.preamble,
addendum: t?.addendum,
germanShortName: recipe.short_name,
translationStatus: recipe.translations.en.translationStatus
}));
translationStatus: t?.translationStatus
}});
return json(JSON.parse(JSON.stringify(englishRecipes)));
}
@@ -24,7 +24,7 @@ function mapBaseRecipeRefs(items: any[]): any[] {
export const GET: RequestHandler = async ({ params }) => {
await dbConnect();
const en = isEnglish(params.recipeLang);
const en = isEnglish(params.recipeLang!);
const query = en
? { 'translations.en.short_name': params.name }
@@ -84,7 +84,7 @@ export const GET: RequestHandler = async ({ params }) => {
}
];
let dbQuery = Recipe.findOne(query);
let dbQuery: any = Recipe.findOne(query);
for (const p of populatePaths) {
dbQuery = dbQuery.populate(p);
}
@@ -7,7 +7,7 @@ import cache from '$lib/server/cache';
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
export const GET: RequestHandler = async ({ params }) => {
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang);
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang!);
const cacheKey = `recipes:${params.recipeLang}:all_brief`;
let recipes: BriefRecipeType[] | null = null;
@@ -17,10 +17,10 @@ export const GET: RequestHandler = async ({ params }) => {
recipes = JSON.parse(cached);
} else {
await dbConnect();
const dbRecipes = await Recipe.find(approvalFilter, projection).lean();
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang));
const dbRecipes: any[] = await Recipe.find(approvalFilter, projection).lean();
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang!));
await cache.set(cacheKey, JSON.stringify(recipes), 3600);
}
return json(JSON.parse(JSON.stringify(rand_array(recipes))));
return json(JSON.parse(JSON.stringify(rand_array(recipes!))));
};
@@ -4,7 +4,7 @@ import { dbConnect } from '$utils/db';
import { isEnglish, briefQueryConfig } from '$lib/server/recipeHelpers';
export const GET: RequestHandler = async ({ params }) => {
const { approvalFilter, prefix } = briefQueryConfig(params.recipeLang);
const { approvalFilter, prefix } = briefQueryConfig(params.recipeLang!);
await dbConnect();
const field = `${prefix}category`;
@@ -5,14 +5,14 @@ import { rand_array } from '$lib/js/randomize';
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
export const GET: RequestHandler = async ({ params }) => {
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang);
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang!);
await dbConnect();
const dbRecipes = await Recipe.find(
const dbRecipes: any[] = await Recipe.find(
{ [`${prefix}category`]: params.category, ...approvalFilter },
projection
).lean();
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang)));
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang!)));
return json(JSON.parse(JSON.stringify(recipes)));
};
@@ -5,7 +5,7 @@ import { rand_array } from '$lib/js/randomize';
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
export const GET: RequestHandler = async ({ params }) => {
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang);
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang!);
await dbConnect();
const dbRecipes = await Recipe.find(
@@ -13,6 +13,6 @@ export const GET: RequestHandler = async ({ params }) => {
projection
).lean();
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang)));
const recipes = rand_array(dbRecipes.map(r => toBrief(r, params.recipeLang!)));
return json(JSON.parse(JSON.stringify(recipes)));
};
@@ -6,7 +6,7 @@ import cache from '$lib/server/cache';
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
export const GET: RequestHandler = async ({ params }) => {
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang);
const { approvalFilter, projection } = briefQueryConfig(params.recipeLang!);
const cacheKey = `recipes:${params.recipeLang}:in_season:${params.month}`;
let recipes = null;
@@ -20,7 +20,7 @@ export const GET: RequestHandler = async ({ params }) => {
{ season: params.month, icon: { $ne: "🍽️" }, ...approvalFilter },
projection
).lean();
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang));
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang!));
await cache.set(cacheKey, JSON.stringify(recipes), 3600);
}
@@ -4,10 +4,10 @@ import { dbConnect } from '$utils/db';
import { isEnglish, briefQueryConfig } from '$lib/server/recipeHelpers';
export const GET: RequestHandler = async ({ params }) => {
const { approvalFilter } = briefQueryConfig(params.recipeLang);
const { approvalFilter } = briefQueryConfig(params.recipeLang!);
await dbConnect();
if (isEnglish(params.recipeLang)) {
if (isEnglish(params.recipeLang!)) {
const recipes = await Recipe.find(approvalFilter, 'translations.en.tags').lean();
const tagsSet = new Set<string>();
recipes.forEach(recipe => {
@@ -6,7 +6,7 @@ import cache from '$lib/server/cache';
import { briefQueryConfig, toBrief } from '$lib/server/recipeHelpers';
export const GET: RequestHandler = async ({ params }) => {
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang);
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang!);
const cacheKey = `recipes:${params.recipeLang}:tag:${params.tag}`;
let recipes = null;
@@ -20,7 +20,7 @@ export const GET: RequestHandler = async ({ params }) => {
{ [`${prefix}tags`]: params.tag, ...approvalFilter },
projection
).lean();
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang));
recipes = dbRecipes.map(r => toBrief(r, params.recipeLang!));
await cache.set(cacheKey, JSON.stringify(recipes), 3600);
}
@@ -7,7 +7,7 @@ import { error } from '@sveltejs/kit';
export const GET: RequestHandler = async ({ params, setHeaders }) => {
await dbConnect();
let recipe = (await Recipe.findOne({ short_name: params.name }).lean()) as RecipeModelType;
let recipe = (await Recipe.findOne({ short_name: params.name }).lean()) as unknown as RecipeModelType;
recipe = JSON.parse(JSON.stringify(recipe));
if (recipe == null) {
@@ -11,7 +11,7 @@ export const GET: RequestHandler = async () => {
const briefRecipes = await Recipe.find(
{},
'name short_name tags category icon description season dateModified images translations'
).lean() as BriefRecipeType[];
).lean() as unknown as BriefRecipeType[];
// Fetch full recipes with populated base recipe references
const fullRecipes = await Recipe.find({})
@@ -39,7 +39,7 @@ export const GET: RequestHandler = async () => {
}
}
})
.lean() as RecipeModelType[];
.lean() as unknown as RecipeModelType[];
// Map populated refs to resolvedRecipe field (same as individual item endpoint)
function mapBaseRecipeRefs(items: any[]): any[] {
@@ -7,8 +7,8 @@ import { isEnglish, briefQueryConfig, toBrief } from '$lib/server/recipeHelpers'
export const GET: RequestHandler = async ({ url, params, locals }) => {
await dbConnect();
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang);
const en = isEnglish(params.recipeLang);
const { approvalFilter, prefix, projection } = briefQueryConfig(params.recipeLang!);
const en = isEnglish(params.recipeLang!);
const query = url.searchParams.get('q')?.toLowerCase().trim() || '';
const category = url.searchParams.get('category');
@@ -46,12 +46,12 @@ export const GET: RequestHandler = async ({ url, params, locals }) => {
}
const dbRecipes = await Recipe.find(dbQuery, projection).lean();
let recipes: BriefRecipeType[] = dbRecipes.map(r => toBrief(r, params.recipeLang));
let recipes: BriefRecipeType[] = dbRecipes.map(r => toBrief(r, params.recipeLang!));
// Handle favorites filter
if (favoritesOnly && locals.session?.user) {
if (favoritesOnly && (locals as any).session?.user) {
const { UserFavorites } = await import('$models/UserFavorites');
const userFavorites = await UserFavorites.findOne({ username: locals.session.user.username });
const userFavorites = await UserFavorites.findOne({ username: (locals as any).session.user.username });
if (userFavorites?.favorites) {
const favoriteIds = userFavorites.favorites;
recipes = recipes.filter(recipe => favoriteIds.some(id => id.toString() === recipe._id?.toString()));
+2 -2
View File
@@ -42,7 +42,7 @@ export const GET: RequestHandler = async ({ locals }) => {
.lean();
// Get all other users who have splits with payments involving the current user
const paymentIds = userSplits.map(split => split.paymentId._id);
const paymentIds = userSplits.map(split => (split.paymentId as any)._id);
const allRelatedSplits = await PaymentSplit.find({
paymentId: { $in: paymentIds },
username: { $ne: currentUser }
@@ -60,7 +60,7 @@ export const GET: RequestHandler = async ({ locals }) => {
// Find other participants in this payment
const otherSplits = allRelatedSplits.filter(s =>
s.paymentId._id.toString() === split.paymentId._id.toString()
(s.paymentId as any)._id.toString() === (split.paymentId as any)._id.toString()
);
for (const otherSplit of otherSplits) {
@@ -76,7 +76,7 @@ export const GET: RequestHandler = async ({ url, locals }) => {
}
];
const results = await Payment.aggregate(pipeline);
const results = await Payment.aggregate(pipeline as any);
// Transform data into chart-friendly format
const monthsMap = new Map();
@@ -106,13 +106,13 @@ export const GET: RequestHandler = async ({ url, locals }) => {
// Convert to arrays for Chart.js
const allMonths = Array.from(monthsMap.keys()).sort();
const categoryList = Array.from(categories).sort();
const categoryList = Array.from(categories).sort() as string[];
// Find the first month with any data and trim empty months from the start
let firstMonthWithData = 0;
for (let i = 0; i < allMonths.length; i++) {
const monthData = monthsMap.get(allMonths[i]);
const hasData = Object.values(monthData).some(value => value > 0);
const hasData = Object.values(monthData).some((value: any) => value > 0);
if (hasData) {
firstMonthWithData = i;
break;
+2 -2
View File
@@ -102,7 +102,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
exchangeRate = conversion.exchangeRate;
} catch (e) {
console.error('Currency conversion error:', e);
throw error(400, `Failed to convert ${inputCurrency} to CHF: ${e.message}`);
throw error(400, `Failed to convert ${inputCurrency} to CHF: ${e instanceof Error ? e.message : String(e)}`);
}
}
@@ -146,7 +146,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
};
});
const splitPromises = convertedSplits.map((split) => {
const splitPromises = convertedSplits.map((split: any) => {
return PaymentSplit.create(split);
});
@@ -36,7 +36,7 @@ export const GET: RequestHandler = async ({ params, locals }) => {
await cache.set(cacheKey, JSON.stringify(result), 1800);
return json(result);
} catch (e) {
} catch (e: any) {
if (e.status === 404) throw e;
throw error(500, 'Failed to fetch payment');
} finally {
@@ -108,7 +108,7 @@ export const PUT: RequestHandler = async ({ params, request, locals }) => {
await invalidateCospendCaches(allAffectedUsers, id);
return json({ success: true, payment: updatedPayment });
} catch (e) {
} catch (e: any) {
if (e.status) throw e;
throw error(500, 'Failed to update payment');
} finally {
@@ -148,7 +148,7 @@ export const DELETE: RequestHandler = async ({ params, locals }) => {
await invalidateCospendCaches(affectedUsernames, id);
return json({ success: true });
} catch (e) {
} catch (e: any) {
if (e.status) throw e;
throw error(500, 'Failed to delete payment');
} finally {
+1 -1
View File
@@ -55,7 +55,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
path: publicPath
});
} catch (err) {
} catch (err: any) {
if (err.status) throw err;
console.error('Upload error:', err);
throw error(500, 'Failed to upload file');
@@ -90,22 +90,22 @@ export const POST: RequestHandler = async ({ request, locals }) => {
// Ensure translations.en.images array exists
if (!recipe.translations) {
recipe.translations = { en: { images: [] } };
(recipe as any).translations = { en: { images: [] } };
}
if (!recipe.translations.en) {
recipe.translations.en = { images: [] };
if (!recipe.translations!.en) {
(recipe.translations as any).en = { images: [] };
}
if (!recipe.translations.en.images) {
recipe.translations.en.images = [];
if (!recipe.translations!.en!.images) {
(recipe.translations!.en as any).images = [];
}
// Ensure array has enough entries
while (recipe.translations.en.images.length <= i) {
recipe.translations.en.images.push({ alt: '', caption: '' });
while (recipe.translations!.en!.images!.length <= i) {
recipe.translations!.en!.images!.push({ alt: '', caption: '' } as any);
}
// Update English alt text
recipe.translations.en.images[i].alt = altTextResult.en;
recipe.translations!.en!.images![i].alt = altTextResult.en;
processed++;
} catch (err) {
+8 -8
View File
@@ -57,22 +57,22 @@ export const POST: RequestHandler = async ({ request, locals }) => {
// Ensure translations.en.images array exists and has the right length
if (!recipe.translations) {
recipe.translations = { en: { images: [] } };
(recipe as any).translations = { en: { images: [] } };
}
if (!recipe.translations.en) {
recipe.translations.en = { images: [] };
if (!recipe.translations!.en) {
(recipe.translations as any).en = { images: [] };
}
if (!recipe.translations.en.images) {
recipe.translations.en.images = [];
if (!recipe.translations!.en!.images) {
(recipe.translations!.en as any).images = [];
}
// Ensure the en.images array has entries for all images
while (recipe.translations.en.images.length <= imageIndex) {
recipe.translations.en.images.push({ alt: '', caption: '' });
while (recipe.translations!.en!.images!.length <= imageIndex) {
recipe.translations!.en!.images!.push({ alt: '', caption: '' } as any);
}
// Update English alt text
recipe.translations.en.images[imageIndex].alt = altTextResult.en;
recipe.translations!.en!.images![imageIndex].alt = altTextResult.en;
// Save to database
await recipe.save();
@@ -14,7 +14,7 @@ export const GET: RequestHandler = async ({ locals }) => {
try {
const streak = await RosaryStreak.findOne({
username: session.user.nickname
}).lean();
}).lean() as any;
return json({
length: streak?.length ?? 0,
@@ -49,11 +49,11 @@ export const POST: RequestHandler = async ({ request, locals }) => {
{ username: session.user.nickname },
{ length, lastPrayed },
{ upsert: true, new: true }
).lean();
).lean() as any;
return json({
length: updated.length,
lastPrayed: updated.lastPrayed
length: updated?.length ?? 0,
lastPrayed: updated?.lastPrayed ?? null
});
} catch (e) {
throw error(500, 'Failed to update rosary streak');
@@ -4,6 +4,20 @@ import { dbConnect } from '$utils/db';
import { MarioKartTournament } from '$models/MarioKartTournament';
import mongoose from 'mongoose';
interface BracketMatch {
_id: string;
contestantIds: string[];
rounds: any[];
completed: boolean;
winnerId?: string;
}
interface BracketRound {
roundNumber: number;
name: string;
matches: BracketMatch[];
}
// POST /api/mario-kart/tournaments/[id]/bracket - Generate tournament bracket
export const POST: RequestHandler = async ({ params, request }) => {
try {
@@ -31,18 +45,18 @@ export const POST: RequestHandler = async ({ params, request }) => {
return json({ error: `Group ${group.name} has no standings yet` }, { status: 400 });
}
const sortedStandings = group.standings.sort((a, b) => a.position - b.position);
const sortedStandings = group.standings.sort((a: any, b: any) => a.position - b.position);
// Top N qualify for main bracket
const topContestants = sortedStandings
.slice(0, topNFromEachGroup)
.map(s => s.contestantId);
.map((s: any) => s.contestantId);
qualifiedContestants.push(...topContestants);
// Remaining contestants go to consolation bracket
const remainingContestants = sortedStandings
.slice(topNFromEachGroup)
.map(s => s.contestantId);
.map((s: any) => s.contestantId);
nonQualifiedContestants.push(...remainingContestants);
}
@@ -57,7 +71,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
const bracketSize = Math.pow(matchSize, Math.ceil(Math.log(qualifiedContestants.length) / Math.log(matchSize)));
// Generate bracket rounds
const rounds = [];
const rounds: BracketRound[] = [];
let currentContestants = bracketSize;
let roundNumber = 1;
@@ -141,7 +155,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
};
// Create consolation bracket for non-qualifiers
const runnersUpRounds = [];
const runnersUpRounds: BracketRound[] = [];
if (nonQualifiedContestants.length >= matchSize) {
// Calculate consolation bracket size
const consolationBracketSize = Math.pow(matchSize, Math.ceil(Math.log(nonQualifiedContestants.length) / Math.log(matchSize)));
@@ -44,7 +44,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
console.error(`Round ${i} has no matches array:`, round);
continue;
}
const foundMatch = round.matches.find(m => m._id?.toString() === params.matchId);
const foundMatch = round.matches.find((m: any) => m._id?.toString() === params.matchId);
if (foundMatch) {
match = foundMatch;
matchRound = round;
@@ -59,7 +59,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
isRunnersUp = true;
for (let i = 0; i < bracket.rounds.length; i++) {
const round = bracket.rounds[i];
const foundMatch = round.matches.find(m => m._id?.toString() === params.matchId);
const foundMatch = round.matches.find((m: any) => m._id?.toString() === params.matchId);
if (foundMatch) {
match = foundMatch;
matchRound = round;
@@ -23,7 +23,7 @@ export const POST: RequestHandler = async ({ params, request }) => {
}
// Check for duplicate names
if (tournament.contestants.some(c => c.name === name)) {
if (tournament.contestants.some((c: any) => c.name === name)) {
return json({ error: 'Contestant with this name already exists' }, { status: 400 });
}
@@ -94,7 +94,7 @@ export const DELETE: RequestHandler = async ({ params, url }) => {
}
tournament.contestants = tournament.contestants.filter(
c => c._id?.toString() !== contestantId
(c: any) => c._id?.toString() !== contestantId
);
await tournament.save();
@@ -23,7 +23,7 @@ export const PATCH: RequestHandler = async ({ params, request }) => {
// Find the contestant in the contestants array
const contestant = tournament.contestants.find(
c => c._id?.toString() === params.contestantId
(c: any) => c._id?.toString() === params.contestantId
);
if (!contestant) {
@@ -21,18 +21,18 @@ export const POST: RequestHandler = async ({ params, request }) => {
return json({ error: 'Tournament not found' }, { status: 404 });
}
const group = tournament.groups.find(g => g._id?.toString() === params.groupId);
const group = tournament.groups.find((g: any) => g._id?.toString() === params.groupId);
if (!group) {
return json({ error: 'Group not found' }, { status: 404 });
}
const match = group.matches.find(m => m._id?.toString() === matchId);
const match = group.matches.find((m: any) => m._id?.toString() === matchId);
if (!match) {
return json({ error: 'Match not found' }, { status: 404 });
}
// Add or update round
const existingRoundIndex = match.rounds.findIndex(r => r.roundNumber === roundNumber);
const existingRoundIndex = match.rounds.findIndex((r: any) => r.roundNumber === roundNumber);
const scoresMap = new Map(Object.entries(scores));
if (existingRoundIndex >= 0) {