|
| 1 | +import type {StrictlyParseSelector} from 'typed-query-selector/parser.js'; |
1 | 2 | import reservedNames from 'github-reserved-names/reserved-names.json' with {type: 'json'}; |
2 | 3 | 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; |
17 | 13 | } |
18 | 14 |
|
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)); |
24 | 17 | } |
25 | 18 |
|
26 | 19 | const combinedTestOnly = ['combinedTestOnly']; // To be used only to skip tests of combined functions, i.e. isPageA() || isPageB() |
@@ -314,7 +307,6 @@ TEST: addTests('isQuickPR', [ |
314 | 307 | 'https://github.com/sindresorhus/refined-github/compare/test-branch?quick_pull=1', |
315 | 308 | ]); |
316 | 309 |
|
317 | | -// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call -- Strict validation may mark complex selectors as potentially invalid |
318 | 310 | const getStateLabel = (): string | undefined => $([ |
319 | 311 | '.State', // Old view |
320 | 312 | // React versions |
@@ -420,7 +412,6 @@ export const isEmptyRepo = (): boolean => exists('[aria-label="Cannot fork becau |
420 | 412 |
|
421 | 413 | export const isPublicRepo = (): boolean => exists('meta[name="octolytics-dimension-repository_public"][content="true"]'); |
422 | 414 |
|
423 | | -// eslint-disable-next-line @typescript-eslint/no-unsafe-call -- Strict validation may mark selectors with child combinators as potentially invalid |
424 | 415 | export const isArchivedRepo = (): boolean => Boolean(isRepo() && $('main > .flash-warn')?.textContent!.includes('archived')); |
425 | 416 |
|
426 | 417 | export const isBlank = (): boolean => exists('main .blankslate:not([hidden] .blankslate)'); |
@@ -880,7 +871,6 @@ TEST: addTests('isNewRepoTemplate', [ |
880 | 871 | ]); |
881 | 872 |
|
882 | 873 | /** 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 |
884 | 874 | const getLoggedInUser = (): string | undefined => $('meta[name="user-login"]')?.getAttribute('content') ?? undefined; |
885 | 875 |
|
886 | 876 | /** Drop all redundant slashes */ |
|
0 commit comments