chore(lint): manual cleanup batch 1/3 (groups 1-5)

- group 1 (catalog.service): rename categoryId→categoryIdInput param + local categoryId; init pl24Categories with Awaited type; fix img alt + scroll buttons
- group 2 (useButtonType): add type=button to 12 buttons (demo.tsx, index.tsx)
- group 3 (noSvgWithoutTitle): add role+aria-label to 13 decorative svgs
- group 4 (noAssignInExpressions): convert 13 while((m=regex.exec())) → for...of matchAll (pl24-ford-legacy + emex.service)
- group 5 (useExhaustiveDependencies): correct deps in __root user identification, subscription onboarding, model-list-columns; biome-ignore for legitimate single-trigger effects

Lint count: 769 → 218

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sase Dev
2026-05-09 16:42:36 +00:00
parent 247efecca6
commit 0af3fbf725
16 changed files with 78 additions and 76 deletions

View File

@@ -652,7 +652,7 @@ export class CatalogService {
if (dbCategories.length === 0 && effectiveCatalogPath) {
try {
let pl24Categories;
let pl24Categories: Awaited<ReturnType<PL24Service["fetchMainGroups"]>>;
if (vehicle.architecture === "LEGACY_PSA") {
// PSA vehicles: parse family/salesType from catalogPath, mode/upds from metadata
@@ -742,7 +742,7 @@ export class CatalogService {
*/
async getCategoryWithParts(
catalogVehicleId: string,
categoryId: string,
categoryIdInput: string,
userId: string,
body = "_all_",
engine = "_all_",
@@ -762,21 +762,27 @@ export class CatalogService {
// PSA variant trees return PL24 codes (e.g. "_FCT0100") as IDs instead of UUIDs.
// Detect and resolve to DB UUID via externalId lookup.
const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(categoryId);
const isUuid =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(categoryIdInput);
let categoryRow: typeof categories.$inferSelect | undefined;
if (isUuid) {
[categoryRow] = await this.db
.select()
.from(categories)
.where(eq(categories.id, categoryId))
.where(eq(categories.id, categoryIdInput))
.limit(1);
} else {
// PSA external code — look up by externalId within this catalog vehicle
[categoryRow] = await this.db
.select()
.from(categories)
.where(and(eq(categories.externalId, categoryId), eq(categories.catalogVehicleId, catalogVehicleId)))
.where(
and(
eq(categories.externalId, categoryIdInput),
eq(categories.catalogVehicleId, catalogVehicleId),
),
)
.limit(1);
}
@@ -784,7 +790,7 @@ export class CatalogService {
// Normalize to DB UUID for all downstream queries
const category = categoryRow;
categoryId = category.id;
const categoryId = category.id;
const linkPath = category.linkPath;

View File

@@ -256,8 +256,7 @@ export class EmexService {
const linkRx = /href="(Vehicle\.aspx\?[^"]+)">([^<]+)<\/a>/g;
const seen = new Set<string>();
const vehicles: EmexHttpVehicle[] = [];
let m: RegExpExecArray | null;
while ((m = linkRx.exec(html)) !== null) {
for (const m of html.matchAll(linkRx)) {
const href = m[1].replace(/&amp;/g, "&");
if (seen.has(href)) continue;
seen.add(href);
@@ -291,8 +290,7 @@ export class EmexService {
const catRx = /href="(QuickDetails\.aspx\?[^"]+)">([^<]+)<\/a>/g;
const seen = new Set<string>();
const cats: EmexHttpCategory[] = [];
let m: RegExpExecArray | null;
while ((m = catRx.exec(html)) !== null) {
for (const m of html.matchAll(catRx)) {
const href = m[1].replace(/&amp;/g, "&");
const name = m[2].trim();
if (name.length < 2 || seen.has(href)) continue;

View File

@@ -2185,8 +2185,7 @@ export class PL24FordLegacyService {
// Scope rows contain jsonUrl="json-main-groups.action?...&scope=_FCT0001&..." and a name cell
const trRegex =
/<tr[^>]+jsonUrl="(json-main-groups\.action[^"]+)"[^>]*>[\s\S]*?<td[^>]*>([^<]+)<\/td>/g;
let m: RegExpExecArray | null;
while ((m = trRegex.exec(html)) !== null) {
for (const m of html.matchAll(trRegex)) {
const jsonUrl = m[1];
const name = m[2].trim();
const scopeMatch = jsonUrl.match(/[?&]scope=([^&]+)/);
@@ -2843,8 +2842,7 @@ export class PL24FordLegacyService {
// These are server-rendered (not JS-injected) — the most reliable source.
const trRegex = /<tr[^>]*\bmodelFamily="([^"]+)"[^>]*\bmodelFamilyName="([^"]+)"/g;
const fromHtmlAttrs: Array<{ id: string; name: string }> = [];
let m: RegExpExecArray | null;
while ((m = trRegex.exec(html)) !== null) {
for (const m of html.matchAll(trRegex)) {
fromHtmlAttrs.push({ id: m[1], name: m[2] });
}
if (fromHtmlAttrs.length > 0) {
@@ -2875,7 +2873,7 @@ export class PL24FordLegacyService {
if (selectMatch) {
const optionRegex = /<option[^>]*value=["']([^"']+)["'][^>]*>([\s\S]*?)<\/option>/gi;
const options: Array<{ id: string; name: string }> = [];
while ((m = optionRegex.exec(selectMatch[1])) !== null) {
for (const m of selectMatch[1].matchAll(optionRegex)) {
const id = m[1].trim();
const name = m[2].replace(/<[^>]+>/g, "").trim();
if (id && id !== "" && id !== "0" && name) {
@@ -2894,8 +2892,7 @@ export class PL24FordLegacyService {
"gi",
);
const modes = new Map<string, string>();
let modeMatch: RegExpExecArray | null;
while ((modeMatch = modeRegex.exec(html)) !== null) {
for (const modeMatch of html.matchAll(modeRegex)) {
const mode = modeMatch[1];
if (mode && !modes.has(mode)) {
modes.set(mode, mode);
@@ -3279,8 +3276,7 @@ export class PL24FordLegacyService {
// Try to extract any text from <td> elements, including those with nested tags
let tdName = "";
const tdPattern = /<td[^>]*>([\s\S]*?)<\/td>/g;
let tdMatch2: RegExpExecArray | null;
while ((tdMatch2 = tdPattern.exec(segment)) !== null) {
for (const tdMatch2 of segment.matchAll(tdPattern)) {
const text = tdMatch2[1]
.replace(/<[^>]+>/g, " ")
.replace(/&nbsp;/g, " ")
@@ -3331,8 +3327,7 @@ export class PL24FordLegacyService {
// Fallback: <a href="...group...action"> links
if (groups.length === 0) {
const linkRegex = /<a[^>]+href="([^"]*group[^"]*\.action[^"]*)"[^>]*>([\s\S]*?)<\/a>/gi;
let match: RegExpExecArray | null;
while ((match = linkRegex.exec(html)) !== null) {
for (const match of html.matchAll(linkRegex)) {
const url = match[1];
const name = match[2].replace(/<[^>]+>/g, "").trim();
if (!name || seen.has(url)) continue;
@@ -3508,8 +3503,7 @@ export class PL24FordLegacyService {
} else {
// Extract text from first non-empty <td> (strip inner tags)
const tdPattern = /<td[^>]*>([\s\S]*?)<\/td>/g;
let tdMatch: RegExpExecArray | null;
while ((tdMatch = tdPattern.exec(segment)) !== null) {
for (const tdMatch of segment.matchAll(tdPattern)) {
const text = tdMatch[1]
.replace(/<[^>]+>/g, " ")
.replace(/&nbsp;/g, " ")
@@ -3568,9 +3562,7 @@ export class PL24FordLegacyService {
extractLinks(html: string, pattern: RegExp): { href: string; text: string }[] {
const linkRegex = /<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi;
const results: { href: string; text: string }[] = [];
let match: RegExpExecArray | null;
while ((match = linkRegex.exec(html)) !== null) {
for (const match of html.matchAll(linkRegex)) {
const href = match[1];
const text = match[2].replace(/<[^>]+>/g, "").trim();
if (pattern.test(href) && text) {
@@ -3596,22 +3588,19 @@ export class PL24FordLegacyService {
// Extract header cells
const headerRegex = /<th[^>]*>([\s\S]*?)<\/th>/gi;
const headers: string[] = [];
let hMatch: RegExpExecArray | null;
while ((hMatch = headerRegex.exec(tableHtml)) !== null) {
for (const hMatch of tableHtml.matchAll(headerRegex)) {
headers.push(hMatch[1].replace(/<[^>]+>/g, "").trim());
}
// Extract rows
const rowRegex = /<tr[^>]*>([\s\S]*?)<\/tr>/gi;
const rows: Record<string, string>[] = [];
let rMatch: RegExpExecArray | null;
let rowIndex = 0;
while ((rMatch = rowRegex.exec(tableHtml)) !== null) {
for (const rMatch of tableHtml.matchAll(rowRegex)) {
const cellRegex = /<td[^>]*>([\s\S]*?)<\/td>/gi;
const cells: string[] = [];
let cMatch: RegExpExecArray | null;
while ((cMatch = cellRegex.exec(rMatch[1])) !== null) {
for (const cMatch of rMatch[1].matchAll(cellRegex)) {
cells.push(cMatch[1].replace(/<[^>]+>/g, "").trim());
}