Skip to content

Commit

Permalink
Update ESLint config with more strict TS rules
Browse files Browse the repository at this point in the history
  • Loading branch information
ai committed Feb 21, 2025
1 parent dcff896 commit f47d617
Show file tree
Hide file tree
Showing 53 changed files with 366 additions and 374 deletions.
2 changes: 1 addition & 1 deletion api/http/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function fetchJSON<Response = unknown>(
throw new Error(await response.text())
}
if (opts.response) opts.response(response)
return response.json()
return response.json() as Response
}

export interface Endpoint<
Expand Down
4 changes: 2 additions & 2 deletions core/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface TextResponse {
readonly contentType: string
readonly headers: Headers
readonly ok: boolean
parseJson(): null | unknown
parseJson(): unknown
parseXml(): Document | null | XMLDocument
readonly redirected: boolean
readonly status: number
Expand Down Expand Up @@ -67,7 +67,7 @@ export function createTextResponse(
}

try {
return JSON.parse(text)
return JSON.parse(text) as unknown
} catch (e) {
if (e instanceof SyntaxError) {
warning('Parse JSON error', e.message)
Expand Down
2 changes: 1 addition & 1 deletion core/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,6 @@ export function getTestEnvironment(): EnvironmentAndStore {
persistentEvents: { addEventListener() {}, removeEventListener() {} },
persistentStore: {},
restartApp: () => {},
translationLoader: async () => ({})
translationLoader: () => Promise.resolve({})
}
}
11 changes: 8 additions & 3 deletions core/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,23 @@ export function getOPMLBlob(): Blob {
return new Blob([opml], { type: 'application/xml' })
}

export async function getInternalBlob(isIncludePosts: Boolean): Promise<Blob> {
export type InternalExport = {
data: [CategoryValue, FeedWithPosts[]][]
type: 'feedsByCategory'
}

export async function getInternalBlob(isIncludePosts: boolean): Promise<Blob> {
$exporting.set(true)
let posts: PostValue[]
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */

if (isIncludePosts) {
posts = await loadValue(getPosts()).then(value => value.list)
}
let enrichedData = $exportingFeedsByCategory
.get()
.map(([category, feeds]: [CategoryValue, FeedWithPosts[]]) => {
let categoryTitle = getCategoryTitle(category)
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */

if (isIncludePosts) {
feeds.forEach(feed => {
feed.posts = posts.filter(post => post.feedId === feed.id)
Expand Down
16 changes: 14 additions & 2 deletions core/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
type CategoryValue,
type FeedsByCategory
} from './category.ts'
import type { InternalExport } from './export.ts'
import { addFeed, type FeedValue } from './feed.ts'
import { readonlyExport } from './lib/stores.ts'
import { unique } from './loader/utils.ts'
import { importMessages } from './messages/index.ts'
import { createFeedFromUrl } from './preview.ts'
import { unique } from './loader/utils.ts'

let $importedFeedsByCategory = atom<FeedsByCategory>([])
export const importedFeedsByCategory = readonlyExport($importedFeedsByCategory)
Expand Down Expand Up @@ -139,6 +140,17 @@ export const toggleImportedFeed = (
$importedFeeds.set(Array.from(selectedFeeds))
}

function isInternalExport(json: unknown): json is InternalExport {
return (
typeof json === 'object' &&
json !== null &&
'type' in json &&
json.type === 'feedsByCategory' &&
'data' in json &&
Array.isArray(json.data)
)
}

export const handleImportFile = (file: File): Promise<void> => {
return new Promise(resolve => {
$reading.set(true)
Expand All @@ -155,7 +167,7 @@ export const handleImportFile = (file: File): Promise<void> => {
if (fileExtension === 'json') {
try {
let jsonData = JSON.parse(content)
if (jsonData.type === 'feedsByCategory') {
if (isInternalExport(jsonData)) {
$importedFeedsByCategory.set(jsonData.data)
importSubscribe()
selectAllImportedFeeds()
Expand Down
5 changes: 4 additions & 1 deletion core/lib/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ export function increaseKey<Store extends MapStore>(
store: Store,
key: NumberKeys<StoreValue<Store>>
): void {
store.setKey(key, store.get()[key] + 1)
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
let value = store.get()[key] as number
store.setKey(key, value + 1)
}

export function listenMany<SourceStores extends ReadableAtom[]>(
stores: [...SourceStores],
cb: (...values: StoreValues<SourceStores>) => void
): () => void {
function listener(): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
let values = stores.map(store => store.get()) as StoreValues<SourceStores>
cb(...values)
}
Expand Down
2 changes: 1 addition & 1 deletion core/loader/json-feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function isObject(value: unknown): value is Record<string, unknown> {
}

function stringify(value: unknown): string {
return typeof value === 'object' ? JSON.stringify(value) : `${value}`
return typeof value === 'object' ? JSON.stringify(value) : String(value)
}

function validate<ValidatedType>(
Expand Down
2 changes: 1 addition & 1 deletion core/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ export const onPreviewUrlType = debounce((value: string) => {
}
}, 500)

export async function setPreviewCandidate(url: string): Promise<void> {
export function setPreviewCandidate(url: string): void {
let candidate = $candidates.get().find(i => i.url === url)
if (candidate) {
$candidate.set(url)
Expand Down
2 changes: 1 addition & 1 deletion core/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function expectRequest(url: string): RequestMock {
expect.response = body
},
andWait() {
let resolveWait: Function
let resolveWait: () => void
expect.wait = new Promise(resolve => {
resolveWait = resolve
})
Expand Down
2 changes: 1 addition & 1 deletion core/test/dom-parser.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { JSDOM } from 'jsdom'

let window = new JSDOM().window
// @ts-expect-error
// @ts-expect-error JSDOM types are incomplete
global.window = window
global.DOMParser = window.DOMParser
global.File = window.File
Expand Down
12 changes: 6 additions & 6 deletions core/test/download.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ test('can download text by keeping eyes on abort signal', async () => {
equal(response1.text, 'Hi')

let sendText: ((text: string) => void) | undefined
setRequestMethod(async url => {
return {
setRequestMethod(url => {
return Promise.resolve({
ok: true,
status: 200,
text() {
Expand All @@ -114,7 +114,7 @@ test('can download text by keeping eyes on abort signal', async () => {
})
},
url: url.toString()
} as Response
} as Response)
})

let response2 = task.text('https://example.com')
Expand All @@ -124,7 +124,7 @@ test('can download text by keeping eyes on abort signal', async () => {
await rejects(response2, (e: Error) => e.name === 'AbortError')
})

test('parses XML content', async () => {
test('parses XML content', () => {
let text = createTextResponse('<html><body>Test</body></html>')
equal(text.parseXml()!.firstChild?.lastChild?.nodeName, 'BODY')
equal(text.parseXml()!.firstChild?.lastChild?.textContent, 'Test')
Expand Down Expand Up @@ -160,7 +160,7 @@ test('parses XML content', async () => {
equal(broken.parseXml()!.textContent, null)
})

test('parses JSON content', async () => {
test('parses JSON content', () => {
let json = createTextResponse('{ "version": "1.1", "title": "test_title" }', {
headers: new Headers({ 'content-type': 'application/json' })
})
Expand Down Expand Up @@ -213,7 +213,7 @@ test('has helper to ignore abort errors', async () => {
ignoreAbortError(error3)
})

test('detects content type', async () => {
test('detects content type', () => {
equal(
createTextResponse('custom', {
headers: new Headers({ 'content-type': 'application/custom' })
Expand Down
8 changes: 4 additions & 4 deletions core/test/export.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ test('initializes with empty states', () => {
equal(exporting.get(), false)
})

test('selects all exporting feeds', async () => {
test('selects all exporting feeds', () => {
selectAllExportingFeeds()

let categories = exportingCategories.get()
Expand All @@ -74,15 +74,15 @@ test('selects all exporting feeds', async () => {
ok(feeds.length > 0)
})

test('clears export selections', async () => {
test('clears export selections', () => {
selectAllExportingFeeds()
clearExportingSelections()

equal(exportingCategories.get().length, 0)
equal(exportingFeeds.get().length, 0)
})

test('toggles exporting category', async () => {
test('toggles exporting category', () => {
let categoryId = 'general'
clearExportingSelections()

Expand All @@ -94,7 +94,7 @@ test('toggles exporting category', async () => {
ok(!exportingCategories.get().includes(categoryId))
})

test('toggles exporting feed', async () => {
test('toggles exporting feed', () => {
let feedId = 'H4RZpnXPjlj_Hzl08ipBw'
let categoryId = 'general'
clearExportingSelections()
Expand Down
6 changes: 3 additions & 3 deletions core/test/i18n.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import { test } from 'node:test'
import { i18n, settingsMessages } from '../index.ts'
import { enableClientTest } from './utils.ts'

test('has i18n', async () => {
test('has i18n', () => {
equal(typeof i18n, 'function')
equal(typeof settingsMessages.get().theme, 'string')

let locale = atom('en')
let loading: string[] = []
enableClientTest({
locale,
async translationLoader(lang) {
translationLoader(lang) {
loading.push(lang)
return {}
return Promise.resolve({})
}
})
locale.set('es')
Expand Down
21 changes: 11 additions & 10 deletions core/test/lib/queue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ test('increase keys', async () => {
await new Promise<void>(resolve => {
resolves.push(resolve)
})
events += payload + 1 + ' '
events += `${payload + 1} `
},
async multiply(payload) {
await new Promise<void>(resolve => {
resolves.push(resolve)
})
events += payload * 2 + ' '
events += `${payload * 2} `
}
})
.then(() => {
Expand Down Expand Up @@ -62,12 +62,14 @@ test('allows to add test in the middle', async () => {
let queue = createQueue<{ a: number; b: number }>([{ payload: 1, type: 'a' }])

await queue.start(2, {
async a(payload, tasks) {
a(payload, tasks) {
tasks.push({ payload: 2, type: 'b' })
events += `a${payload} `
return Promise.resolve()
},
async b(payload) {
b(payload) {
events += `b${payload} `
return Promise.resolve()
}
})

Expand Down Expand Up @@ -125,13 +127,12 @@ test('reties on error', async () => {
equal(errorReport, 1)
})

test('passes thrown string', async () => {
test('passes thrown string', () => {
let attempts = 0
rejects(async () => {
await retryOnError(
() => {
attempts += 1
// eslint-disable-next-line no-throw-literal
throw 'error string'
},
() => {
Expand Down Expand Up @@ -167,10 +168,10 @@ test('returns value after error', async () => {
let errorReport = 0
let attempts = 0
let result = await retryOnError(
async () => {
() => {
attempts += 1
if (attempts === 2) {
return 'ok'
return Promise.resolve('ok')
} else {
throw new Error('test')
}
Expand All @@ -189,9 +190,9 @@ test('returns value on no error', async () => {
let errorReport = 0
let attempts = 0
let result = await retryOnError(
async () => {
() => {
attempts += 1
return 'ok'
return Promise.resolve('ok')
},
() => {
errorReport += 1
Expand Down
14 changes: 8 additions & 6 deletions core/test/loader/atom.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ test('ignores text & comment nodes when probing', () => {
)
})

test('parses posts', async () => {
test('parses posts', () => {
let task = createDownloadTask()
deepStrictEqual(
loaders.atom
Expand Down Expand Up @@ -360,18 +360,20 @@ test('parses posts', async () => {

test('loads text to parse posts', async () => {
let task = createDownloadTask()
let text = spyOn(task, 'text', async () =>
exampleAtom(
`<?xml version="1.0"?>
let text = spyOn(task, 'text', () => {
return Promise.resolve(
exampleAtom(
`<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Feed</title>
<entry>
<title>1</title>
<id>1</id>
</entry>
</feed>`
)
)
)
})
let page = loaders.atom.getPosts(task, 'https://example.com/news/')
deepStrictEqual(page.get(), {
hasNext: true,
Expand All @@ -398,7 +400,7 @@ test('loads text to parse posts', async () => {
deepStrictEqual(text.calls, [['https://example.com/news/']])
})

test('parses media', async () => {
test('parses media', () => {
let task = createDownloadTask()
deepStrictEqual(
loaders.atom
Expand Down
Loading

0 comments on commit f47d617

Please sign in to comment.