Typescript v5 + eslint 8.57 WIP
This commit also improves some type handling in the project.
This commit is contained in:
@ -59,7 +59,7 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
||||
|
||||
logger.info(`Channel ${channelId} deleted, removing 'custom emojis' related stuff.`)
|
||||
try {
|
||||
Emojis.singletonSafe()?.deleteChannelDefinition(channelId)
|
||||
await Emojis.singletonSafe()?.deleteChannelDefinition(channelId)
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
}
|
||||
@ -87,7 +87,7 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
||||
])
|
||||
|
||||
await fillVideoCustomFields(options, video)
|
||||
const hasChat = await videoHasWebchat({
|
||||
const hasChat = videoHasWebchat({
|
||||
'chat-per-live-video': !!settings['chat-per-live-video'],
|
||||
'chat-all-lives': !!settings['chat-all-lives'],
|
||||
'chat-all-non-lives': !!settings['chat-all-non-lives'],
|
||||
|
@ -17,31 +17,36 @@ import { channelTermsMaxLength } from '../../../../shared/lib/constants'
|
||||
async function sanitizeChannelConfigurationOptions (
|
||||
_options: RegisterServerOptions,
|
||||
_channelId: number | string,
|
||||
data: any
|
||||
data: unknown
|
||||
): Promise<ChannelConfigurationOptions> {
|
||||
if (typeof data !== 'object') {
|
||||
if (!_assertObjectType(data)) {
|
||||
throw new Error('Invalid data type')
|
||||
}
|
||||
|
||||
const botData = data.bot
|
||||
if (typeof botData !== 'object') {
|
||||
const botData = data.bot ?? {}
|
||||
if (!_assertObjectType(botData)) {
|
||||
throw new Error('Invalid data.bot data type')
|
||||
}
|
||||
|
||||
// slowMode not present in livechat <= 8.2.0:
|
||||
const slowModeData = data.slowMode ?? {}
|
||||
slowModeData.duration ??= slowModeData.defaultDuration ?? 0 // v8.3.0 to 8.3.2: was in defaultDuration
|
||||
|
||||
if (typeof slowModeData !== 'object') {
|
||||
if (!_assertObjectType(slowModeData)) {
|
||||
throw new Error('Invalid data.slowMode data type')
|
||||
}
|
||||
slowModeData.duration ??= slowModeData.defaultDuration ?? 0 // v8.3.0 to 8.3.2: was in defaultDuration
|
||||
|
||||
const moderationData = data.moderation ?? {} // comes with livechat 10.3.0
|
||||
if (!_assertObjectType(moderationData)) {
|
||||
throw new Error('Invalid data.moderation data type')
|
||||
}
|
||||
moderationData.delay ??= 0
|
||||
moderationData.anonymize ??= false // comes with livechat 11.0.0
|
||||
|
||||
// mute not present in livechat <= 10.2.0
|
||||
const mute = data.mute ?? {}
|
||||
if (!_assertObjectType(mute)) {
|
||||
throw new Error('Invalid data.mute data type')
|
||||
}
|
||||
mute.anonymous ??= false
|
||||
|
||||
// forbidSpecialChars comes with livechat 11.1.0
|
||||
@ -51,13 +56,12 @@ async function sanitizeChannelConfigurationOptions (
|
||||
tolerance: 0,
|
||||
applyToModerators: false
|
||||
}
|
||||
|
||||
if (typeof mute !== 'object') {
|
||||
throw new Error('Invalid data.mute data type')
|
||||
if (!_assertObjectType(botData.forbidSpecialChars)) {
|
||||
throw new Error('Invalid data.forbidSpecialChars data type')
|
||||
}
|
||||
|
||||
// terms not present in livechat <= 10.2.0
|
||||
let terms = data.terms
|
||||
let terms = data.terms ?? undefined
|
||||
if (terms !== undefined && (typeof terms !== 'string')) {
|
||||
throw new Error('Invalid data.terms data type')
|
||||
}
|
||||
@ -94,7 +98,11 @@ async function sanitizeChannelConfigurationOptions (
|
||||
return result
|
||||
}
|
||||
|
||||
function _readBoolean (data: any, f: string): boolean {
|
||||
function _assertObjectType (data: unknown): data is Record<string, unknown> {
|
||||
return !!data && (typeof data === 'object') && Object.keys(data).every(k => typeof k === 'string')
|
||||
}
|
||||
|
||||
function _readBoolean (data: Record<string, unknown>, f: string): boolean {
|
||||
if (!(f in data)) {
|
||||
return false
|
||||
}
|
||||
@ -104,11 +112,11 @@ function _readBoolean (data: any, f: string): boolean {
|
||||
return data[f]
|
||||
}
|
||||
|
||||
function _readInteger (data: any, f: string, min: number, max: number): number {
|
||||
function _readInteger (data: Record<string, unknown>, f: string, min: number, max: number): number {
|
||||
if (!(f in data)) {
|
||||
throw new Error('Missing integer value for field ' + f)
|
||||
}
|
||||
const v = parseInt(data[f])
|
||||
const v = typeof data[f] === 'number' ? Math.trunc(data[f]) : parseInt(data[f] as string)
|
||||
if (isNaN(v)) {
|
||||
throw new Error('Invalid value type for field ' + f)
|
||||
}
|
||||
@ -121,7 +129,7 @@ function _readInteger (data: any, f: string, min: number, max: number): number {
|
||||
return v
|
||||
}
|
||||
|
||||
function _readSimpleInput (data: any, f: string, strict?: boolean, noSpace?: boolean): string {
|
||||
function _readSimpleInput (data: Record<string, unknown>, f: string, strict?: boolean, noSpace?: boolean): string {
|
||||
if (!(f in data)) {
|
||||
return ''
|
||||
}
|
||||
@ -130,7 +138,7 @@ function _readSimpleInput (data: any, f: string, strict?: boolean, noSpace?: boo
|
||||
}
|
||||
// Removing control characters.
|
||||
// eslint-disable-next-line no-control-regex
|
||||
let s = (data[f] as string).replace(/[\u0000-\u001F\u007F-\u009F]/g, '')
|
||||
let s = data[f].replace(/[\u0000-\u001F\u007F-\u009F]/g, '')
|
||||
if (strict) {
|
||||
// Replacing all invalid characters, no need to throw an error..
|
||||
s = s.replace(/[^\p{L}\p{N}\p{Z}_-]$/gu, '')
|
||||
@ -141,7 +149,7 @@ function _readSimpleInput (data: any, f: string, strict?: boolean, noSpace?: boo
|
||||
return s
|
||||
}
|
||||
|
||||
function _readStringArray (data: any, f: string): string[] {
|
||||
function _readStringArray (data: Record<string, unknown>, f: string): string[] {
|
||||
if (!(f in data)) {
|
||||
return []
|
||||
}
|
||||
@ -162,7 +170,7 @@ function _readStringArray (data: any, f: string): string[] {
|
||||
return result
|
||||
}
|
||||
|
||||
function _readMultiLineString (data: any, f: string): string {
|
||||
function _readMultiLineString (data: Record<string, unknown>, f: string): string {
|
||||
if (!(f in data)) {
|
||||
return ''
|
||||
}
|
||||
@ -171,11 +179,11 @@ function _readMultiLineString (data: any, f: string): string {
|
||||
}
|
||||
// Removing control characters (must authorize \u001A: line feed)
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const s = (data[f] as string).replace(/[\u0000-\u0009\u001B-\u001F\u007F-\u009F]/g, '')
|
||||
const s = data[f].replace(/[\u0000-\u0009\u001B-\u001F\u007F-\u009F]/g, '')
|
||||
return s
|
||||
}
|
||||
|
||||
async function _readRegExpArray (data: any, f: string): Promise<string[]> {
|
||||
async function _readRegExpArray (data: Record<string, unknown>, f: string): Promise<string[]> {
|
||||
// Note: this function can instanciate a lot of RegExp.
|
||||
// To avoid freezing the server, we make it async, and will validate each regexp in a separate tick.
|
||||
if (!(f in data)) {
|
||||
@ -195,11 +203,11 @@ async function _readRegExpArray (data: any, f: string): Promise<string[]> {
|
||||
}
|
||||
// value must be a valid regexp
|
||||
try {
|
||||
async function _validate (): Promise<void> {
|
||||
async function _validate (v: string): Promise<void> {
|
||||
// eslint-disable-next-line no-new
|
||||
new RegExp(v)
|
||||
}
|
||||
await _validate()
|
||||
await _validate(v)
|
||||
} catch (_err) {
|
||||
throw new Error('Invalid value in field ' + f)
|
||||
}
|
||||
@ -208,12 +216,17 @@ async function _readRegExpArray (data: any, f: string): Promise<string[]> {
|
||||
return result
|
||||
}
|
||||
|
||||
async function _readForbiddenWords (botData: any): Promise<ChannelConfigurationOptions['bot']['forbiddenWords']> {
|
||||
async function _readForbiddenWords (
|
||||
botData: Record<string, unknown>
|
||||
): Promise<ChannelConfigurationOptions['bot']['forbiddenWords']> {
|
||||
if (!Array.isArray(botData.forbiddenWords)) {
|
||||
throw new Error('Invalid forbiddenWords data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['forbiddenWords'] = []
|
||||
for (const fw of botData.forbiddenWords) {
|
||||
if (!_assertObjectType(fw)) {
|
||||
throw new Error('Invalid entry in botData.forbiddenWords')
|
||||
}
|
||||
const regexp = !!fw.regexp
|
||||
let entries
|
||||
if (regexp) {
|
||||
@ -239,9 +252,9 @@ async function _readForbiddenWords (botData: any): Promise<ChannelConfigurationO
|
||||
}
|
||||
|
||||
async function _readForbidSpecialChars (
|
||||
botData: any
|
||||
botData: Record<string, unknown>
|
||||
): Promise<ChannelConfigurationOptions['bot']['forbidSpecialChars']> {
|
||||
if (typeof botData.forbidSpecialChars !== 'object') {
|
||||
if (!_assertObjectType(botData.forbidSpecialChars)) {
|
||||
throw new Error('Invalid forbidSpecialChars data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['forbidSpecialChars'] = {
|
||||
@ -253,12 +266,15 @@ async function _readForbidSpecialChars (
|
||||
return result
|
||||
}
|
||||
|
||||
function _readQuotes (botData: any): ChannelConfigurationOptions['bot']['quotes'] {
|
||||
function _readQuotes (botData: Record<string, unknown>): ChannelConfigurationOptions['bot']['quotes'] {
|
||||
if (!Array.isArray(botData.quotes)) {
|
||||
throw new Error('Invalid quotes data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['quotes'] = []
|
||||
for (const qs of botData.quotes) {
|
||||
if (!_assertObjectType(qs)) {
|
||||
throw new Error('Invalid entry in botData.quotes')
|
||||
}
|
||||
const messages = _readStringArray(qs, 'messages')
|
||||
const delay = _readInteger(qs, 'delay', 1, 6000)
|
||||
|
||||
@ -270,12 +286,15 @@ function _readQuotes (botData: any): ChannelConfigurationOptions['bot']['quotes'
|
||||
return result
|
||||
}
|
||||
|
||||
function _readCommands (botData: any): ChannelConfigurationOptions['bot']['commands'] {
|
||||
function _readCommands (botData: Record<string, unknown>): ChannelConfigurationOptions['bot']['commands'] {
|
||||
if (!Array.isArray(botData.commands)) {
|
||||
throw new Error('Invalid commands data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['commands'] = []
|
||||
for (const cs of botData.commands) {
|
||||
if (!_assertObjectType(cs)) {
|
||||
throw new Error('Invalid entry in botData.commands')
|
||||
}
|
||||
const message = _readSimpleInput(cs, 'message')
|
||||
const command = _readSimpleInput(cs, 'command', false, true)
|
||||
|
||||
|
@ -140,7 +140,7 @@ function channelConfigurationOptionsToBotRoomConf (
|
||||
for (const handler of previousRoomConf.handlers) {
|
||||
if (!handlersIds.has(handler.id)) {
|
||||
// cloning to avoid issues...
|
||||
const disabledHandler = JSON.parse(JSON.stringify(handler))
|
||||
const disabledHandler = JSON.parse(JSON.stringify(handler)) as typeof handler
|
||||
disabledHandler.enabled = false
|
||||
handlers.push(disabledHandler)
|
||||
}
|
||||
|
Reference in New Issue
Block a user