stricter ESLint configuration, linebreak on stylistic per deprecation by ESLint, fixed changes. add attibutes to prevent blockade.

This commit is contained in:
theofficialomega
2025-07-28 22:28:48 +02:00
parent 88652ab1ae
commit e3c7a372f2
41 changed files with 8471 additions and 8424 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Enforce the usage of CRLF in GitHub Actions per ESLint configuration.
* text eol=crlf

View File

@@ -1,4 +1,5 @@
import typescriptEslint from '@typescript-eslint/eslint-plugin' import typescriptEslint from '@typescript-eslint/eslint-plugin'
import stylistic from '@stylistic/eslint-plugin'
import globals from 'globals' import globals from 'globals'
import tsParser from '@typescript-eslint/parser' import tsParser from '@typescript-eslint/parser'
import path from 'node:path' import path from 'node:path'
@@ -15,10 +16,11 @@ const compat = new FlatCompat({
}) })
export default [ export default [
...compat.extends('eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'), ...compat.extends('eslint:recommended', 'plugin:@typescript-eslint/strict', 'plugin:@typescript-eslint/stylistic', 'prettier'),
{ {
plugins: { plugins: {
'@typescript-eslint': typescriptEslint '@typescript-eslint': typescriptEslint,
'@stylistic': stylistic
}, },
languageOptions: { languageOptions: {
@@ -36,7 +38,7 @@ export default [
'@typescript-eslint/no-require-imports': 'off', '@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-var-requires': 'off',
'no-case-declarations': 'off', 'no-case-declarations': 'off',
'linebreak-style': ['error', process.env.CI ? 'unix' : 'windows'], '@stylistic/linebreak-style': ['error', 'windows'],
quotes: [ quotes: [
'error', 'error',

45
package-lock.json generated
View File

@@ -18,6 +18,7 @@
"@octokit/core": "^7.0.3", "@octokit/core": "^7.0.3",
"@octokit/plugin-paginate-rest": "^13.1.1", "@octokit/plugin-paginate-rest": "^13.1.1",
"@octokit/plugin-rest-endpoint-methods": "^16.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0",
"@stylistic/eslint-plugin": "^5.2.2",
"@swc/core": "^1.13.2", "@swc/core": "^1.13.2",
"@swc/jest": "^0.2.39", "@swc/jest": "^0.2.39",
"@types/cli-progress": "^3.11.6", "@types/cli-progress": "^3.11.6",
@@ -3146,6 +3147,50 @@
"@sinonjs/commons": "^3.0.1" "@sinonjs/commons": "^3.0.1"
} }
}, },
"node_modules/@stylistic/eslint-plugin": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.2.2.tgz",
"integrity": "sha512-bE2DUjruqXlHYP3Q2Gpqiuj2bHq7/88FnuaS0FjeGGLCy+X6a07bGVuwtiOYnPSLHR6jmx5Bwdv+j7l8H+G97A==",
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/types": "^8.37.0",
"eslint-visitor-keys": "^4.2.1",
"espree": "^10.4.0",
"estraverse": "^5.3.0",
"picomatch": "^4.0.3"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"peerDependencies": {
"eslint": ">=9.0.0"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/eslint-visitor-keys": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
"integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"license": "Apache-2.0",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@stylistic/eslint-plugin/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@swc/core": { "node_modules/@swc/core": {
"version": "1.13.2", "version": "1.13.2",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.2.tgz", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.2.tgz",

View File

@@ -46,6 +46,7 @@
"@octokit/core": "^7.0.3", "@octokit/core": "^7.0.3",
"@octokit/plugin-paginate-rest": "^13.1.1", "@octokit/plugin-paginate-rest": "^13.1.1",
"@octokit/plugin-rest-endpoint-methods": "^16.0.0", "@octokit/plugin-rest-endpoint-methods": "^16.0.0",
"@stylistic/eslint-plugin": "^5.2.2",
"@swc/core": "^1.13.2", "@swc/core": "^1.13.2",
"@swc/jest": "^0.2.39", "@swc/jest": "^0.2.39",
"@types/cli-progress": "^3.11.6", "@types/cli-progress": "^3.11.6",

View File

@@ -13,8 +13,8 @@ import epgGrabber from 'epg-grabber'
import { Command } from 'commander' import { Command } from 'commander'
import readline from 'readline' import readline from 'readline'
type ChoiceValue = { type: string; value?: Feed | Channel } interface ChoiceValue { type: string; value?: Feed | Channel }
type Choice = { name: string; short?: string; value: ChoiceValue; default?: boolean } interface Choice { name: string; short?: string; value: ChoiceValue; default?: boolean }
if (process.platform === 'win32') { if (process.platform === 'win32') {
readline readline

View File

@@ -12,7 +12,7 @@ program
.option('-o, --output <output>', 'Output file') .option('-o, --output <output>', 'Output file')
.parse(process.argv) .parse(process.argv)
type ParseOptions = { interface ParseOptions {
config: string config: string
set?: string set?: string
output?: string output?: string
@@ -43,9 +43,7 @@ async function main() {
channelList = await parser.parse(outputFilepath) channelList = await parser.parse(outputFilepath)
} }
const args: { const args: Record<string, string> = {}
[key: string]: string
} = {}
if (Array.isArray(options.set)) { if (Array.isArray(options.set)) {
options.set.forEach((arg: string) => { options.set.forEach((arg: string) => {

View File

@@ -11,7 +11,7 @@ import langs from 'langs'
program.argument('[filepath...]', 'Path to *.channels.xml files to validate').parse(process.argv) program.argument('[filepath...]', 'Path to *.channels.xml files to validate').parse(process.argv)
type ValidationError = { interface ValidationError {
type: 'duplicate' | 'wrong_channel_id' | 'wrong_feed_id' | 'wrong_lang' type: 'duplicate' | 'wrong_channel_id' | 'wrong_feed_id' | 'wrong_lang'
name: string name: string
lang?: string lang?: string

View File

@@ -48,7 +48,7 @@ program
.addOption(new Option('--curl', 'Display each request as CURL').default(false).env('CURL')) .addOption(new Option('--curl', 'Display each request as CURL').default(false).env('CURL'))
.parse() .parse()
export type GrabOptions = { export interface GrabOptions {
site?: string site?: string
channels?: string channels?: string
output: string output: string

View File

@@ -2,7 +2,7 @@ import { parseChannels } from 'epg-grabber'
import { Storage } from '@freearhey/core' import { Storage } from '@freearhey/core'
import { ChannelList } from '../models' import { ChannelList } from '../models'
type ChannelsParserProps = { interface ChannelsParserProps {
storage: Storage storage: Storage
} }

View File

@@ -3,7 +3,6 @@ import { DataLoaderData } from '../types/dataLoader'
import { Collection } from '@freearhey/core' import { Collection } from '@freearhey/core'
export class DataProcessor { export class DataProcessor {
constructor() {}
process(data: DataLoaderData) { process(data: DataLoaderData) {
let channels = new Collection(data.channels).map(data => new Channel(data)) let channels = new Collection(data.channels).map(data => new Channel(data))

View File

@@ -5,7 +5,7 @@ import { GrabOptions } from '../commands/epg/grab'
import { TaskQueue, PromisyClass } from 'cwait' import { TaskQueue, PromisyClass } from 'cwait'
import { SocksProxyAgent } from 'socks-proxy-agent' import { SocksProxyAgent } from 'socks-proxy-agent'
type GrabberProps = { interface GrabberProps {
logger: Logger logger: Logger
queue: Queue queue: Queue
options: GrabOptions options: GrabOptions

View File

@@ -8,7 +8,7 @@ import { DataLoaderData } from '../types/dataLoader'
import { DataProcessorData } from '../types/dataProcessor' import { DataProcessorData } from '../types/dataProcessor'
import { DATA_DIR } from '../constants' import { DATA_DIR } from '../constants'
type GuideManagerProps = { interface GuideManagerProps {
options: OptionValues options: OptionValues
logger: Logger logger: Logger
channels: Collection channels: Collection

View File

@@ -1,4 +1,4 @@
type Column = { interface Column {
name: string name: string
nowrap?: boolean nowrap?: boolean
align?: string align?: string

View File

@@ -2,7 +2,7 @@ import { Logger } from '@freearhey/core'
import { Queue, Grabber, GuideManager } from '.' import { Queue, Grabber, GuideManager } from '.'
import { GrabOptions } from '../commands/epg/grab' import { GrabOptions } from '../commands/epg/grab'
type JobProps = { interface JobProps {
options: GrabOptions options: GrabOptions
logger: Logger logger: Logger
queue: Queue queue: Queue

View File

@@ -1,6 +1,6 @@
import { URL } from 'node:url' import { URL } from 'node:url'
type ProxyParserResult = { interface ProxyParserResult {
protocol: string | null protocol: string | null
auth?: { auth?: {
username?: string username?: string

View File

@@ -1,7 +1,7 @@
import { Dictionary } from '@freearhey/core' import { Dictionary } from '@freearhey/core'
import { SiteConfig, Channel } from 'epg-grabber' import { SiteConfig, Channel } from 'epg-grabber'
export type QueueItem = { export interface QueueItem {
channel: Channel channel: Channel
date: string date: string
config: SiteConfig config: SiteConfig

View File

@@ -5,7 +5,7 @@ import { ConfigLoader, Queue } from './'
import { SiteConfig } from 'epg-grabber' import { SiteConfig } from 'epg-grabber'
import path from 'path' import path from 'path'
type QueueCreatorProps = { interface QueueCreatorProps {
logger: Logger logger: Logger
options: GrabOptions options: GrabOptions
channels: Collection channels: Collection

View File

@@ -28,10 +28,10 @@ export const sortBy = <T>(arr: T[], fn: (item: T) => number | string): T[] =>
* // [{name: 'bob', age: 30}, {name: 'john', age: 30}, {name: 'jane', age: 25}] * // [{name: 'bob', age: 30}, {name: 'john', age: 30}, {name: 'jane', age: 25}]
*/ */
export const orderBy = ( export const orderBy = (
arr: Array<unknown>, arr: unknown[],
fns: Array<(item: unknown) => string | number>, fns: ((item: unknown) => string | number)[],
orders: Array<string> = [] orders: string[] = []
): Array<unknown> => ): unknown[] =>
[...arr].sort((a, b) => [...arr].sort((a, b) =>
fns.reduce( fns.reduce(
(acc, fn, i) => (acc, fn, i) =>

View File

@@ -12,7 +12,7 @@ export class Channel {
subdivisionCode?: string subdivisionCode?: string
cityName?: string cityName?: string
categoryIds?: Collection categoryIds?: Collection
isNSFW: boolean = false isNSFW = false
launched?: string launched?: string
closed?: string closed?: string
replacedBy?: string replacedBy?: string
@@ -116,7 +116,7 @@ export class Channel {
} }
function format(logo: Logo): number { function format(logo: Logo): number {
const levelByFormat: { [key: string]: number } = { const levelByFormat: Record<string, number> = {
SVG: 0, SVG: 0,
PNG: 3, PNG: 3,
APNG: 1, APNG: 1,

View File

@@ -29,7 +29,7 @@ export class ChannelList {
} }
toString() { toString() {
function escapeString(value: string, defaultValue: string = '') { function escapeString(value: string, defaultValue = '') {
if (!value) return defaultValue if (!value) return defaultValue
const regex = new RegExp( const regex = new RegExp(

View File

@@ -87,7 +87,7 @@ export class Feed {
getLogos(): Collection { getLogos(): Collection {
function format(logo: Logo): number { function format(logo: Logo): number {
const levelByFormat: { [key: string]: number } = { const levelByFormat: Record<string, number> = {
SVG: 0, SVG: 0,
PNG: 3, PNG: 3,
APNG: 1, APNG: 1,

View File

@@ -1,7 +1,7 @@
import { Collection, DateTime } from '@freearhey/core' import { Collection, DateTime } from '@freearhey/core'
import { generateXMLTV } from 'epg-grabber' import { generateXMLTV } from 'epg-grabber'
type GuideData = { interface GuideData {
channels: Collection channels: Collection
programs: Collection programs: Collection
filepath: string filepath: string

View File

@@ -1,7 +1,7 @@
import { Dictionary } from '@freearhey/core' import { Dictionary } from '@freearhey/core'
import { OWNER, REPO } from '../constants' import { OWNER, REPO } from '../constants'
type IssueProps = { interface IssueProps {
number: number number: number
labels: string[] labels: string[]
data: Dictionary data: Dictionary

View File

@@ -7,8 +7,8 @@ export class Logo {
feedId?: string feedId?: string
feed?: Feed feed?: Feed
tags: Collection = new Collection() tags: Collection = new Collection()
width: number = 0 width = 0
height: number = 0 height = 0
format?: string format?: string
url?: string url?: string

View File

@@ -7,12 +7,12 @@ enum StatusCode {
OK = 'ok' OK = 'ok'
} }
type Status = { interface Status {
code: StatusCode code: StatusCode
emoji: string emoji: string
} }
type SiteProps = { interface SiteProps {
domain: string domain: string
totalChannels?: number totalChannels?: number
markedChannels?: number markedChannels?: number

View File

@@ -16,8 +16,8 @@ export class Stream {
isInterlaced?: boolean isInterlaced?: boolean
referrer?: string referrer?: string
userAgent?: string userAgent?: string
groupTitle: string = 'Undefined' groupTitle = 'Undefined'
removed: boolean = false removed = false
constructor(data: StreamData) { constructor(data: StreamData) {
const id = data.channel && data.feed ? [data.channel, data.feed].join('@') : data.channel const id = data.channel && data.feed ? [data.channel, data.feed].join('@') : data.channel

View File

@@ -1,6 +1,6 @@
import { Collection } from '@freearhey/core' import { Collection } from '@freearhey/core'
export type ChannelData = { export interface ChannelData {
id: string id: string
name: string name: string
alt_names: string[] alt_names: string[]
@@ -17,7 +17,7 @@ export type ChannelData = {
website: string website: string
} }
export type ChannelSearchableData = { export interface ChannelSearchableData {
id: string id: string
name: string name: string
altNames: string[] altNames: string[]

View File

@@ -1,10 +1,10 @@
import { Storage } from '@freearhey/core' import { Storage } from '@freearhey/core'
export type DataLoaderProps = { export interface DataLoaderProps {
storage: Storage storage: Storage
} }
export type DataLoaderData = { export interface DataLoaderData {
countries: object | object[] countries: object | object[]
regions: object | object[] regions: object | object[]
subdivisions: object | object[] subdivisions: object | object[]

View File

@@ -1,6 +1,6 @@
import { Collection, Dictionary } from '@freearhey/core' import { Collection, Dictionary } from '@freearhey/core'
export type DataProcessorData = { export interface DataProcessorData {
guideChannelsGroupedByStreamId: Dictionary guideChannelsGroupedByStreamId: Dictionary
feedsGroupedByChannelId: Dictionary feedsGroupedByChannelId: Dictionary
logosGroupedByChannelId: Dictionary logosGroupedByChannelId: Dictionary

View File

@@ -1,6 +1,6 @@
import { Collection } from '@freearhey/core' import { Collection } from '@freearhey/core'
export type FeedData = { export interface FeedData {
channel: string channel: string
id: string id: string
name: string name: string

View File

@@ -1,4 +1,4 @@
export type GuideData = { export interface GuideData {
channel: string channel: string
feed: string feed: string
site: string site: string

View File

@@ -1,4 +1,4 @@
export type LogoData = { export interface LogoData {
channel: string channel: string
feed: string | null feed: string | null
tags: string[] tags: string[]

View File

@@ -1,4 +1,4 @@
export type StreamData = { export interface StreamData {
channel: string | null channel: string | null
feed: string | null feed: string | null
name?: string name?: string

View File

@@ -1,6 +1,6 @@
import { execSync } from 'child_process' import { execSync } from 'child_process'
type ExecError = { interface ExecError {
status: number status: number
stdout: string stdout: string
} }

View File

@@ -1,6 +1,6 @@
import { execSync } from 'child_process' import { execSync } from 'child_process'
type ExecError = { interface ExecError {
status: number status: number
stdout: string stdout: string
} }