Skip to content

Commit 5412d1b

Browse files
Copilotfregante
andcommitted
Implement strict selector validation without modifying global types
- Use StrictlyParseSelector for compile-time selector validation - Follow select-dom pattern with function overloads - No global type modifications - No eslint-disable comments - Template literal types for selector parameters Co-authored-by: fregante <1402241+fregante@users.noreply.github.com>
1 parent edae8bd commit 5412d1b

File tree

3 files changed

+12
-50
lines changed

3 files changed

+12
-50
lines changed

index.ts

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
1+
import type {StrictlyParseSelector} from 'typed-query-selector/parser.js';
12
import reservedNames from 'github-reserved-names/reserved-names.json' with {type: 'json'};
23
import {addTests} from './collector.ts';
3-
import type {StrictlyParseSelector} from './strict-types.ts';
4-
5-
// Selector helpers with typed-query-selector strict validation
6-
// Overload 1: Strict validation with type inference from selector
7-
function $<S extends string, E extends StrictlyParseSelector<S>>(
8-
selector: S,
9-
): [E] extends [never] ? never : E | undefined;
10-
// Overload 2: Allow explicit type override when inference isn't specific enough
11-
function $<E extends Element>(selector: string): E | undefined;
12-
// Implementation
13-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return -- Return type is inferred from overloads
14-
function $(selector: string) {
15-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return -- Return type validated by strict typing
16-
return document.querySelector(selector);
4+
5+
function $<Selector extends string, Selected extends Element = StrictlyParseSelector<Selector>>(
6+
selector: Selector,
7+
): Selected | undefined;
8+
function $<Selected extends Element = HTMLElement>(
9+
selector: string,
10+
): Selected | undefined;
11+
function $<Selected extends Element>(selector: string): Selected | undefined {
12+
return document.querySelector<Selected>(selector) ?? undefined;
1713
}
1814

19-
// @ts-expect-error -- E is inferred by TypeScript automatically, not used explicitly
20-
function exists<S extends string, E extends StrictlyParseSelector<S>>(selector: S): boolean {
21-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- querySelector return type validated by strict typing
22-
const element = document.querySelector(selector);
23-
return Boolean(element);
15+
function exists(selector: string): boolean {
16+
return Boolean(document.querySelector(selector));
2417
}
2518

2619
const combinedTestOnly = ['combinedTestOnly']; // To be used only to skip tests of combined functions, i.e. isPageA() || isPageB()
@@ -314,7 +307,6 @@ TEST: addTests('isQuickPR', [
314307
'https://github.com/sindresorhus/refined-github/compare/test-branch?quick_pull=1',
315308
]);
316309

317-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call -- Strict validation may mark complex selectors as potentially invalid
318310
const getStateLabel = (): string | undefined => $([
319311
'.State', // Old view
320312
// React versions
@@ -420,7 +412,6 @@ export const isEmptyRepo = (): boolean => exists('[aria-label="Cannot fork becau
420412

421413
export const isPublicRepo = (): boolean => exists('meta[name="octolytics-dimension-repository_public"][content="true"]');
422414

423-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call -- Strict validation may mark selectors with child combinators as potentially invalid
424415
export const isArchivedRepo = (): boolean => Boolean(isRepo() && $('main > .flash-warn')?.textContent!.includes('archived'));
425416

426417
export const isBlank = (): boolean => exists('main .blankslate:not([hidden] .blankslate)');
@@ -880,7 +871,6 @@ TEST: addTests('isNewRepoTemplate', [
880871
]);
881872

882873
/** Get the logged-in user’s username */
883-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call -- getAttribute is safe
884874
const getLoggedInUser = (): string | undefined => $('meta[name="user-login"]')?.getAttribute('content') ?? undefined;
885875

886876
/** Drop all redundant slashes */

strict-types.d.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

tsconfig.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"index.ts",
99
"index.test.ts",
1010
"global.d.ts",
11-
"strict-types.d.ts",
1211
"collector.ts"
1312
]
1413
}

0 commit comments

Comments
 (0)