Merge pull request 'Sonarqube cleanup 3' (#3529) from sonarqube-cleanup3 into develop

Reviewed-on: https://git.pleroma.social/pleroma/pleroma-fe/pulls/3529
This commit is contained in:
HJ 2026-08-04 18:36:11 +00:00
commit 3561d206f1
59 changed files with 204 additions and 319 deletions

View file

@ -35,7 +35,7 @@ const getAllAccessibleAnnotations = async (projectRoot) => {
}),
)
)
.filter((k) => k)
.filter(Boolean)
.join(',\n')
return `

View file

@ -237,10 +237,10 @@ export const changeStatusScope = ({
credentials,
}) => {
const payload = {}
if (typeof sensitive !== 'undefined') {
if (sensitive !== undefined) {
payload['sensitive'] = sensitive
}
if (typeof visibility !== 'undefined') {
if (visibility !== undefined) {
payload['visibility'] = visibility
}
@ -260,15 +260,15 @@ export const announcementToPayload = ({
}) => {
const payload = { content }
if (typeof startsAt !== 'undefined') {
if (startsAt !== undefined) {
payload.starts_at = startsAt ? new Date(startsAt).toISOString() : null
}
if (typeof endsAt !== 'undefined') {
if (endsAt !== undefined) {
payload.ends_at = endsAt ? new Date(endsAt).toISOString() : null
}
if (typeof allDay !== 'undefined') {
if (allDay !== undefined) {
payload.all_day = allDay
}

View file

@ -18,7 +18,7 @@ export const chats = ({ credentials }) =>
url: PLEROMA_CHATS_URL,
credentials,
}).then(({ data }) => ({
data: data.map(parseChat).filter((c) => c),
data: data.map(parseChat).filter(Boolean),
}))
export const getOrCreateChat = ({ accountId, credentials }) =>
@ -40,7 +40,7 @@ export const chatMessages = ({
method: 'GET',
credentials,
}).then(({ data }) => ({
data: data.map(parseChatMessage).filter((c) => c),
data: data.map(parseChatMessage).filter(Boolean),
}))
}

View file

@ -37,11 +37,7 @@ export const paramsString = (params = {}) => {
arrays.forEach(([k, array]) => {
array.forEach((v) => {
if (
typeof v === 'object' ||
typeof v === 'function' ||
typeof v === 'undefined'
)
if (typeof v === 'object' || typeof v === 'function' || v === undefined)
throw new TypeError('Array param cannot contain non-primitives!')
})
})

View file

@ -97,7 +97,7 @@ const Chat = {
mounted() {
window.addEventListener('resize', this.handleResize)
window.addEventListener('scroll', this.handleScroll)
if (typeof document.hidden !== 'undefined') {
if (document.hidden !== undefined) {
document.addEventListener(
'visibilitychange',
this.handleVisibilityChange,
@ -112,7 +112,7 @@ const Chat = {
unmounted() {
window.removeEventListener('scroll', this.handleScroll)
window.removeEventListener('resize', this.handleResize)
if (typeof document.hidden !== 'undefined')
if (document.hidden !== undefined)
document.removeEventListener(
'visibilitychange',
this.handleVisibilityChange,

View file

@ -11,11 +11,11 @@
{{ label }}
</label>
<Checkbox
v-if="typeof fallback !== 'undefined' && showOptionalCheckbox && !hideOptionalCheckbox"
v-if="fallback !== undefined && showOptionalCheckbox && !hideOptionalCheckbox"
:model-value="present"
:disabled="disabled"
class="opt"
@update:model-value="updateValue(typeof modelValue === 'undefined' ? fallback : undefined)"
@update:model-value="updateValue(modelValue === undefined ? fallback : undefined)"
/>
<div
class="input color-input-field"

View file

@ -62,7 +62,7 @@ const sortAndFilterConversation = (conversation, statusoid) => {
} else {
conversation = filter(conversation, (status) => status.type !== 'retweet')
}
return conversation.filter((_) => _).sort(sortById)
return conversation.filter(Boolean).sort(sortById)
}
const conversation = {
@ -239,9 +239,9 @@ const conversation = {
depth,
},
walk(forest, forest[id], depth + 1, processed),
].reduce((a, b) => a.concat(b), [])
].flat()
})
.reduce((a, b) => a.concat(b), [])
.flat()
const linearized = walk(
threads.forest,
@ -305,11 +305,10 @@ const conversation = {
topLevel() {
const topLevel = this.conversation.reduce(
(tl, cur) =>
tl.filter(
(k) =>
this.getReplies(cur.id)
.map((v) => v.id)
.indexOf(k.id) === -1,
tl.filter((k) =>
this.getReplies(cur.id)
.map((v) => v.id)
.includes(k.id),
),
this.conversation,
)

View file

@ -188,8 +188,8 @@ const EmojiInput = {
}
return {
names: names.filter((k) => k),
keywords: keywords.filter((k) => k),
names: names.filter(Boolean),
keywords: keywords.filter(Boolean),
}
}
},

View file

@ -57,7 +57,7 @@ const maybeLocalizedKeywords = (emoji, languages, nameLocalizer) => {
languages.forEach((lang) => {
const keywords = emoji.annotations[lang]?.keywords || []
const name = emoji.annotations[lang]?.name
res.push(...keywords.concat([name]).filter((k) => k))
res.push(...keywords.concat([name]).filter(Boolean))
})
}
return res
@ -408,7 +408,7 @@ const EmojiPicker = {
isFirstRow: index === 0,
})),
)
.reduce((a, c) => a.concat(c), [])
.flat()
},
languages() {
return ensureFinalFallback(

View file

@ -35,7 +35,7 @@ export default {
'sans-serif',
'monospace',
...(this.options || []),
].filter((_) => _),
].filter(Boolean),
}
},
methods: {

View file

@ -2,7 +2,7 @@
<div class="font-control">
<div class="setting-item">
<Checkbox
v-if="typeof fallback !== 'undefined'"
v-if="fallback !== undefined"
:id="name + '-o'"
class="font-checkbox setting-control setting-label"
:model-value="present"

View file

@ -59,12 +59,12 @@ const ListsNew = {
membersUsers() {
return [...this.membersUserIds, ...this.addedUserIds]
.map((userId) => this.findUser(userId))
.filter((user) => user)
.filter(Boolean)
},
searchUsers() {
return this.searchUserIds
.map((userId) => this.findUser(userId))
.filter((user) => user)
.filter(Boolean)
},
...mapState({
currentUser: (state) => state.users.currentUser,

View file

@ -11,7 +11,7 @@
{{ label || $t('settings.style.themes3.editor.opacity') }}
</label>
<Checkbox
v-if="typeof fallback !== 'undefined'"
v-if="fallback !== undefined"
:model-value="present"
:disabled="disabled"
class="opt"

View file

@ -11,7 +11,7 @@
{{ label }}
</label>
<input
v-if="typeof fallback !== 'undefined'"
v-if="fallback !== undefined"
:id="name + '-o'"
:aria-labelledby="name + '-label'"
class="input -checkbox opt visible-for-screenreader-only"
@ -20,7 +20,7 @@
@change="$emit('update:modelValue', !present ? fallback : undefined)"
>
<label
v-if="typeof fallback !== 'undefined'"
v-if="fallback !== undefined"
class="opt-l"
:for="name + '-o'"
:aria-hidden="true"

View file

@ -128,7 +128,7 @@ const registration = {
this.user.captcha_answer_data = this.captcha.answer_data
if (this.user.language) {
this.user.language = localeService.internalToBackendLocaleMulti(
this.user.language.filter((k) => k),
this.user.language.filter(Boolean),
)
}

View file

@ -381,13 +381,13 @@ export default {
x ? 'mfm-spinX' : null,
y ? 'mfm-spinY' : null,
'mfm-spin',
].filter((a) => a)[0]
].filter(Boolean)[0]
const direction = [
alternate ? 'alternate' : null,
left ? 'reverse' : null,
'normal',
].filter((a) => a)[0]
].filter(Boolean)[0]
newAttrs.style = [
`animation-name: ${anim}`,

View file

@ -11,7 +11,7 @@
{{ label }}
</label>
<Checkbox
v-if="typeof fallback !== 'undefined'"
v-if="fallback !== undefined"
:model-value="present"
:disabled="disabled"
class="opt"

View file

@ -122,7 +122,7 @@ const EmojiTab = {
return this.refreshPackList()
} else {
this.displayError(resp.error)
return Promise.reject(resp)
throw new Error(resp)
}
})
.then(() => {
@ -139,7 +139,7 @@ const EmojiTab = {
return this.refreshPackList()
} else {
this.displayError(resp.error)
return Promise.reject(resp)
throw new Error(resp)
}
})
.then(() => {
@ -239,7 +239,7 @@ const EmojiTab = {
return this.refreshPackList()
} else {
this.displayError(resp.error)
return Promise.reject(resp)
throw new Error(resp)
}
})
.then(() => {
@ -259,7 +259,7 @@ const EmojiTab = {
return this.refreshPackList()
} else {
this.displayError(resp.error)
return Promise.reject(resp)
throw new Error(resp)
}
})
.then(() => {
@ -280,7 +280,7 @@ const EmojiTab = {
return this.refreshPackList()
} else {
this.displayError(resp.error)
return Promise.reject(resp)
throw new Error(resp)
}
})
.then(() => {

View file

@ -262,7 +262,7 @@ export default {
.then((resp) => {
if (resp.error !== undefined) {
this.$emit('displayError', resp.error)
return Promise.reject(resp.error)
throw new Error(resp.error)
}
return resp.json()

View file

@ -28,12 +28,12 @@ export default {
methods: {
...Setting.methods,
getValue(e) {
if (!this.truncate === 1) {
if (this.truncate === 1) {
return Number.parseInt(e.target.value)
} else if (this.truncate > 1) {
return Math.trunc(e.target.value / this.truncate) * this.truncate
}
return parseFloat(e.target.value)
return Number.parseFloat(e.target.value)
},
},
}

View file

@ -67,7 +67,10 @@ export default {
return this.$t(['settings', 'units', this.unitSet, value].join('.'))
},
updateValue(e) {
this.configSink(this.path, parseFloat(e.target.value) + this.stateUnit)
this.configSink(
this.path,
Number.parseFloat(e.target.value) + this.stateUnit,
)
},
updateUnit(e) {
let value = this.stateValue

View file

@ -236,7 +236,7 @@ const AppearanceTab = {
},
stylePalettes() {
const ruleset = useInterfaceStore().styleDataUsed || []
if (!ruleset?.length === 0) return
if (ruleset.length === 0) return
const meta = ruleset.find((x) => x.component === '@meta')
const result = ruleset
.filter((x) => x.component.startsWith('@palette'))
@ -277,7 +277,7 @@ const AppearanceTab = {
return !window.IntersectionObserver
},
instanceWallpaper() {
useInstanceStore().instanceIdentity.background
return useInstanceStore().instanceIdentity.background
},
instanceWallpaperUsed() {
return (

View file

@ -1,5 +1,4 @@
import { mapActions, mapState } from 'pinia'
import { v4 as uuidv4 } from 'uuid'
import { mapState } from 'pinia'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import Select from 'src/components/select/select.vue'
@ -12,7 +11,6 @@ import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
const ClutterTab = {
components: {
@ -33,120 +31,6 @@ const ClutterTab = {
store.instanceIdentity.showInstanceSpecificPanel &&
store.instanceIdentity.instanceSpecificPanelContent,
}),
...mapState(useSyncConfigStore, {
muteFilters: (store) =>
Object.entries(store.prefsStorage.simple.muteFilters),
muteFiltersObject: (store) => store.prefsStorage.simple.muteFilters,
}),
},
methods: {
...mapActions(useSyncConfigStore, [
'setSimplePrefAndSave',
'unsetSimplePrefAndSave',
'pushSyncConfig',
]),
getDatetimeLocal(timestamp) {
const date = new Date(timestamp)
const fmt = new Intl.NumberFormat('en-US', { minimumIntegerDigits: 2 })
const datetime = [
date.getFullYear(),
'-',
fmt.format(date.getMonth() + 1),
'-',
fmt.format(date.getDate()),
'T',
fmt.format(date.getHours()),
':',
fmt.format(date.getMinutes()),
].join('')
return datetime
},
checkRegexValid(id) {
const filter = this.muteFiltersObject[id]
if (filter.type !== 'regexp') return true
if (filter.type !== 'user_regexp') return true
const { value } = filter
let valid = true
try {
new RegExp(value)
} catch {
valid = false
console.error('Invalid RegExp: ' + value)
}
return valid
},
createFilter(
filter = {
type: 'word',
value: '',
name: 'New Filter',
enabled: true,
expires: null,
hide: false,
},
) {
const newId = uuidv4()
filter.order = this.muteFilters.length + 2
this.muteFiltersDraftObject[newId] = filter
this.setSimplePrefAndSave({ path: 'muteFilters.' + newId, value: filter })
this.pushSyncConfig()
},
exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] }
delete this.exportedFilter.order
this.filterExporter.exportData()
},
importFilter() {
this.filterImporter.importData()
},
copyFilter(id) {
const filter = { ...this.muteFiltersDraftObject[id] }
const newId = uuidv4()
this.muteFiltersDraftObject[newId] = filter
this.setSimplePrefAndSave({ path: 'muteFilters.' + newId, value: filter })
this.pushSyncConfig()
},
deleteFilter(id) {
delete this.muteFiltersDraftObject[id]
this.unsetSimplePrefAndSave({ path: 'muteFilters.' + id, value: null })
this.pushSyncConfig()
},
purgeExpiredFilters() {
this.muteFiltersExpired.forEach(([id]) => {
delete this.muteFiltersDraftObject[id]
this.unsetSimplePrefAndSave({ path: 'muteFilters.' + id, value: null })
})
this.pushSyncConfig()
},
updateFilter(id, field, value) {
const filter = { ...this.muteFiltersDraftObject[id] }
if (field === 'expires-never') {
if (!value) {
const offset = 1000 * 60 * 60 * 24 * 14 // 2 weeks
const date = Date.now() + offset
filter.expires = date
} else {
filter.expires = null
}
} else if (field === 'expires') {
const parsed = Date.parse(value)
filter.expires = parsed.valueOf()
} else {
filter[field] = value
}
this.muteFiltersDraftObject[id] = filter
this.muteFiltersDraftDirty[id] = true
},
saveFilter(id) {
this.setSimplePrefAndSave({
path: 'muteFilters.' + id,
value: this.muteFiltersDraftObject[id],
})
this.pushSyncConfig()
this.muteFiltersDraftDirty[id] = false
},
},
// Updating nested properties
watch: {

View file

@ -190,21 +190,24 @@ const FilteringTab = {
}
return valid
},
createFilter(
filter = {
createFilter(filter) {
const newId = uuidv4()
const newFilter = {
type: 'word',
value: '',
name: 'New Filter',
enabled: true,
expires: null,
hide: false,
},
) {
const newId = uuidv4()
...filter,
}
filter.order = this.muteFilters.length + 2
this.muteFiltersDraftObject[newId] = filter
this.setSimplePrefAndSave({ path: 'muteFilters.' + newId, value: filter })
newFilter.order = this.muteFilters.length + 2
this.muteFiltersDraftObject[newId] = newFilter
this.setSimplePrefAndSave({
path: 'muteFilters.' + newId,
value: newFilter,
})
},
exportFilter(id) {
this.exportedFilter = { ...this.muteFiltersDraftObject[id] }

View file

@ -611,7 +611,7 @@ export default {
*/
normalizeLocalState(theme, version = 0, source, forceSource = false) {
let input
if (typeof source !== 'undefined') {
if (source !== undefined) {
if (forceSource || source?.themeEngineVersion === CURRENT_VERSION) {
input = source
version = source.themeEngineVersion

View file

@ -181,14 +181,14 @@
name="accentColor"
:fallback="previewTheme.colors?.link"
:label="$t('settings.accent')"
:show-optional-checkbox="typeof linkColorLocal !== 'undefined'"
:show-optional-checkbox="linkColorLocal !== undefined"
/>
<ColorInput
v-model="linkColorLocal"
name="linkColor"
:fallback="previewTheme.colors?.accent"
:label="$t('settings.links')"
:show-optional-checkbox="typeof accentColorLocal !== 'undefined'"
:show-optional-checkbox="accentColorLocal !== undefined"
/>
<ContrastRatio :contrast="previewContrast.bgLink" />
</div>

View file

@ -262,7 +262,7 @@ const Status = {
this.muteFilterHits.length > 0 ? 'filtered' : null,
this.muteBotStatuses && this.botStatus ? 'bot' : null,
this.muteSensitiveStatuses && this.sensitiveStatus ? 'nsfw' : null,
].filter((_) => _)
].filter(Boolean)
},
muteLocalized() {
if (this.muteReasons.length === 0) return null

View file

@ -1,7 +1,7 @@
#!/usr/bin/env node
const arg = process.argv[2]
if (typeof arg === 'undefined') {
if (arg === undefined) {
console.info('This is a very simple and tiny tool that checks en.json with any other language and')
console.info('outputs all the things present in english but missing in foreign language.')
console.info('')

View file

@ -20,7 +20,7 @@ const languageFileMap = import.meta.glob(['./*.json', '!./en.json'])
const loadLanguageFile = (code) => {
const jsonName = langCodeToJsonName(code)
if (jsonName === 'en') return Promise.resolve({ default: enMessages })
if (jsonName === 'en') return { default: enMessages }
return languageFileMap[`./${jsonName}.json`]()
}

View file

@ -74,7 +74,7 @@ export default function createPersistedState({
if (saveImmedeatelyActions.includes(mutation.type)) {
setState(key, reducer(cloneDeep(state), paths), storage).then(
(success) => {
if (typeof success !== 'undefined') {
if (success !== undefined) {
if (
mutation.type === 'setOption' ||
mutation.type === 'setCurrentUser'
@ -198,7 +198,7 @@ export const piniaPersistPlugin =
const setState = (state) => {
if (!loadedGuard.loaded) {
console.info('waiting for old state to be loaded...')
return Promise.reject()
throw new Error('Waiting')
} else {
return storage.setItem(key, state)
}

View file

@ -325,7 +325,7 @@ const api = {
const token = state.wsToken
if (
useInstanceCapabilitiesStore().shoutAvailable &&
typeof token !== 'undefined' &&
token !== undefined &&
state.socket === null
) {
const socket = new Socket('/socket', { params: { token } })

View file

@ -49,8 +49,8 @@ const emptyTl = (userId = 0) => ({
visibleStatuses: [],
visibleStatusesObject: {},
newStatusCount: 0,
maxId: 0,
minId: 0,
maxId: '0',
minId: '0',
minVisibleId: 0,
loading: false,
followers: [],
@ -64,7 +64,7 @@ export const defaultState = () => ({
scrobblesNextFetch: {},
allStatusesObject: {},
conversationsObject: {},
maxId: 0,
maxId: '0',
favorites: new Set(),
timelines: {
mentions: emptyTl(),
@ -525,7 +525,7 @@ export const mutations = {
},
addRepeats(state, { id, rebloggedByUsers, currentUser }) {
const newStatus = state.allStatusesObject[id]
newStatus.rebloggedBy = rebloggedByUsers.filter((_) => _)
newStatus.rebloggedBy = rebloggedByUsers.filter(Boolean)
// repeats stats can be incorrect based on polling condition, let's update them using the most recent data
newStatus.repeat_num = newStatus.rebloggedBy.length
newStatus.repeated = !!newStatus.rebloggedBy.find(
@ -534,7 +534,7 @@ export const mutations = {
},
addFavs(state, { id, favoritedByUsers, currentUser }) {
const newStatus = state.allStatusesObject[id]
newStatus.favoritedBy = favoritedByUsers.filter((_) => _)
newStatus.favoritedBy = favoritedByUsers.filter(Boolean)
// favorites stats can be incorrect based on polling condition, let's update them using the most recent data
newStatus.fave_num = newStatus.favoritedBy.length
newStatus.favorited = !!newStatus.favoritedBy.find(
@ -879,7 +879,7 @@ const statuses = {
store.commit('addNewUsers', data.accounts)
store.commit(
'addNewUsers',
data.statuses.map((s) => s.user).filter((u) => u),
data.statuses.map((s) => s.user).filter(Boolean),
)
store.commit('addNewStatuses', {
statuses: data.statuses,

View file

@ -76,10 +76,10 @@ const mergeArrayLength = (oldValue, newValue) => {
const getNotificationPermission = () => {
const Notification = window.Notification
if (!Notification) return Promise.resolve(null)
if (!Notification) return null
if (Notification.permission === 'default')
return Notification.requestPermission()
return Promise.resolve(Notification.permission)
return Notification.permission
}
const blockUser = (store, args) => {
@ -269,7 +269,7 @@ export const mutations = {
state.currentUser.blockIds = blockIds
},
addBlockId(state, blockId) {
if (state.currentUser.blockIds.indexOf(blockId) === -1) {
if (state.currentUser.blockIds.includes(blockId)) {
state.currentUser.blockIds.push(blockId)
}
},
@ -283,7 +283,7 @@ export const mutations = {
state.currentUser.muteIdsMaxId = muteIdsMaxId
},
addMuteId(state, muteId) {
if (state.currentUser.muteIds.indexOf(muteId) === -1) {
if (state.currentUser.muteIds.includes(muteId)) {
state.currentUser.muteIds.push(muteId)
}
},
@ -291,7 +291,7 @@ export const mutations = {
state.currentUser.domainMutes = domainMutes
},
addDomainMute(state, domain) {
if (state.currentUser.domainMutes.indexOf(domain) === -1) {
if (state.currentUser.domainMutes.includes(domain)) {
state.currentUser.domainMutes.push(domain)
}
},
@ -388,7 +388,7 @@ const users = {
if (!user) {
return store.dispatch('fetchUser', id)
} else {
return Promise.resolve(user)
return user
}
},
updateUserAdminData(store, { userAdminData }) {
@ -635,7 +635,7 @@ const users = {
},
addNewNotifications(store, { notifications }) {
const users = map(notifications, 'from_profile')
const targetUsers = map(notifications, 'target').filter((_) => _)
const targetUsers = map(notifications, 'target').filter(Boolean)
const notificationIds = notifications.map((_) => _.id)
store.commit('addNewUsers', users)
store.commit('addNewUsers', targetUsers)

View file

@ -11,7 +11,7 @@ import { contrastRatio, convert, invertLightness } from 'chromatism'
* @param {Number} [b] - Blue component
*/
export const rgb2hex = (r, g, b) => {
if (r === null || typeof r === 'undefined') {
if (r === null || r === undefined) {
return undefined
}
// TODO: clean up this mess
@ -130,7 +130,7 @@ export const arithmeticBlend = (origin, value, operator) => {
* @returns {Object} sRGB of resulting color
*/
export const alphaBlend = (fg, fga, bg) => {
if (fga === 1 || typeof fga === 'undefined') {
if (fga === 1 || fga === undefined) {
return fg
}
@ -210,16 +210,16 @@ export const rgba2css = function (rgba) {
}
if (rgba !== null) {
if (rgba.r !== undefined && !isNaN(rgba.r)) {
if (rgba.r !== undefined && !Number.isNaN(rgba.r)) {
base.r = rgba.r
}
if (rgba.g !== undefined && !isNaN(rgba.g)) {
if (rgba.g !== undefined && !Number.isNaN(rgba.g)) {
base.g = rgba.g
}
if (rgba.b !== undefined && !isNaN(rgba.b)) {
if (rgba.b !== undefined && !Number.isNaN(rgba.b)) {
base.b = rgba.b
}
if (rgba.a !== undefined && !isNaN(rgba.a)) {
if (rgba.a !== undefined && !Number.isNaN(rgba.a)) {
base.a = rgba.a
}
} else {

View file

@ -43,7 +43,7 @@ export const fileTypeExt = (url) => {
}
export const fileMatchesSomeType = (types, file) =>
types.some((type) => fileType(file.mimetype) === type)
types.includes(fileType(file.mimetype))
const fileTypeService = {
fileType,

View file

@ -25,7 +25,7 @@ const visibleTypes = (notificationVisibility) => {
notificationVisibility.emojiReactions && 'pleroma:emoji_reaction',
notificationVisibility.reports && 'pleroma:report',
notificationVisibility.polls && 'poll',
].filter((_) => _)
].filter(Boolean)
}
const statusNotifications = new Set([
@ -95,9 +95,7 @@ export const filteredNotificationsFromStore = (
types,
) => {
// map is just to clone the array since sort mutates it and it causes some issues
const sortedNotifications = notificationsFromStore(store)
.map((_) => _)
.sort(sortById)
const sortedNotifications = notificationsFromStore(store).sort(sortById)
// TODO implement sorting elsewhere and make it optional
return sortedNotifications.filter((notification) =>
(types || visibleTypes(notificationVisibility)).includes(notification.type),

View file

@ -25,13 +25,13 @@ const createRuffleService = () => {
script.src = '/static/ruffle/ruffle.js'
script.type = 'text/javascript'
script.onerror = (e) => {
reject(e)
reject(new Error('Ruffle script errorred', e))
}
script.onabort = (e) => {
reject(e)
reject(new Error('Ruffle script aborted', e))
}
script.oncancel = (e) => {
reject(e)
reject(new Error('Ruffle script cancelled', e))
}
script.onload = () => {
ruffleInstance = window.RufflePlayer

View file

@ -88,5 +88,5 @@ export const muteFilterHits = (muteFilters, status) => {
}
}
})
.filter((_) => _)
.filter(Boolean)
}

View file

@ -316,7 +316,7 @@ export const getResourcesIndex = async (url, parser = (x) => x) => {
const resourceTransform = (resources) => {
return Object.entries(resources).map(([k, v]) => {
if (typeof v === 'object') {
return [k, () => Promise.resolve(v)]
return [k, () => v]
} else if (typeof v === 'string') {
return [
k,
@ -359,11 +359,9 @@ export const getResourcesIndex = async (url, parser = (x) => x) => {
const total = [...custom, ...builtin]
if (total.length === 0) {
return Promise.reject(
new Error(
`Resource at ${url} and ${customUrl} completely unavailable. Panicking`,
),
throw new Error(
`Resource at ${url} and ${customUrl} completely unavailable. Panicking`,
)
}
return Promise.resolve(Object.fromEntries(total))
return Object.fromEntries(total)
}

View file

@ -3,7 +3,7 @@ function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - (base64String.length % 4)) % 4)
const base64 = (base64String + padding)
.replaceAll('-', '+')
.replace(/_/g, '/')
.replaceAll('_', '/')
const rawData = window.atob(base64)
return Uint8Array.from([...rawData].map((char) => char.codePointAt(0)))
@ -28,10 +28,8 @@ function getOrCreateServiceWorker() {
}
function subscribePush(registration, isEnabled, vapidPublicKey) {
if (!isEnabled)
return Promise.reject(new Error('Web Push is disabled in config'))
if (!vapidPublicKey)
return Promise.reject(new Error('VAPID public key is not found'))
if (!isEnabled) throw new Error('Web Push is disabled in config')
if (!vapidPublicKey) throw new Error('VAPID public key is not found')
const subscribeOptions = {
userVisibleOnly: false,
@ -40,10 +38,10 @@ function subscribePush(registration, isEnabled, vapidPublicKey) {
return registration.pushManager.subscribe(subscribeOptions)
}
function unsubscribePush(registration) {
async function unsubscribePush(registration) {
return registration.pushManager.getSubscription().then((subscription) => {
if (subscription === null) {
return Promise.resolve('No subscription')
return 'No subscription'
}
return subscription.unsubscribe()
})

View file

@ -165,7 +165,7 @@ export const getCssRules = (rules, debug) =>
header,
directives,
rule.component === 'Text' &&
rule.state.indexOf('faint') < 0 &&
!rule.state.includes('faint') &&
rule.directives.textNoCssColor !== 'yes'
? ' color: var(--text);'
: '',

View file

@ -24,7 +24,7 @@ export const getAllPossibleCombinations = (array) => {
const nonSelf = array.filter((x) => !selfSet.has(x))
return nonSelf.map((x) => [...self, x])
})
const flatCombos = newCombos.reduce((acc, x) => [...acc, ...x], [])
const flatCombos = newCombos.flat()
const uniqueComboStrings = new Set()
const uniqueCombos = flatCombos.map(sortBy).filter((x) => {
if (uniqueComboStrings.has(x.join())) {
@ -36,7 +36,7 @@ export const getAllPossibleCombinations = (array) => {
})
combos.push(uniqueCombos)
}
return combos.reduce((acc, x) => [...acc, ...x], [])
return combos.flat()
}
/**

View file

@ -191,14 +191,16 @@ export const convertTheme2To3 = (data) => {
newRules.push(rule)
if (rule.component === 'Button') {
newRules.push({ ...rule, component: 'ScrollbarElement' })
newRules.push({ ...rule, component: 'Tab' })
newRules.push({
...rule,
component: 'Tab',
state: ['active'],
directives: { opacity: 0 },
})
newRules.push(
{ ...rule, component: 'ScrollbarElement' },
{ ...rule, component: 'Tab' },
{
...rule,
component: 'Tab',
state: ['active'],
directives: { opacity: 0 },
},
)
}
if (rule.component === 'Panel') {
newRules.push({ ...rule, component: 'Post' })
@ -250,8 +252,10 @@ export const convertTheme2To3 = (data) => {
}
newRules.push(rule)
if (rule.component === 'Button') {
newRules.push({ ...rule, component: 'ScrollbarElement' })
newRules.push({ ...rule, component: 'Tab' })
newRules.push(
{ ...rule, component: 'ScrollbarElement' },
{ ...rule, component: 'Tab' },
)
}
})
return newRules
@ -349,16 +353,20 @@ export const convertTheme2To3 = (data) => {
newRules.push({ ...rule, parent: { component: 'Notification' } })
}
if (key === 'buttonPressed') {
newRules.push({ ...rule, state: ['toggled'] })
newRules.push({ ...rule, state: ['toggled', 'focus'] })
newRules.push({ ...rule, state: ['pressed', 'focus'] })
newRules.push({ ...rule, state: ['toggled', 'focus', 'hover'] })
newRules.push({ ...rule, state: ['pressed', 'focus', 'hover'] })
newRules.push(
{ ...rule, state: ['toggled'] },
{ ...rule, state: ['toggled', 'focus'] },
{ ...rule, state: ['pressed', 'focus'] },
{ ...rule, state: ['toggled', 'focus', 'hover'] },
{ ...rule, state: ['pressed', 'focus', 'hover'] },
)
}
if (rule.component === 'Button') {
newRules.push({ ...rule, component: 'ScrollbarElement' })
newRules.push({ ...rule, component: 'Tab' })
newRules.push(
{ ...rule, component: 'ScrollbarElement' },
{ ...rule, component: 'Tab' },
)
}
})
return newRules
@ -512,15 +520,17 @@ export const convertTheme2To3 = (data) => {
{ ...newRule, component: 'Tab' },
{ ...newRule, component: 'ScrollbarElement' },
]
if (newRule.state?.indexOf('toggled') >= 0) {
rules.push({ ...newRule, state: [...newRule.state, 'focused'] })
rules.push({ ...newRule, state: [...newRule.state, 'hover'] })
rules.push({
...newRule,
state: [...newRule.state, 'hover', 'focused'],
})
if (newRule.state?.includes('toggled')) {
rules.push(
{ ...newRule, state: [...newRule.state, 'focused'] },
{ ...newRule, state: [...newRule.state, 'hover'] },
{
...newRule,
state: [...newRule.state, 'hover', 'focused'],
},
)
}
if (newRule.state?.indexOf('hover') >= 0) {
if (newRule.state?.includes('hover')) {
rules.push({ ...newRule, state: [...newRule.state, 'focused'] })
}
return rules
@ -559,9 +569,9 @@ export const convertTheme2To3 = (data) => {
const flatExtRules = extendedRules
.filter(Boolean)
.reduce((acc, x) => [...acc, ...x], [])
.flat()
.filter(Boolean)
.reduce((acc, x) => [...acc, ...x], [])
.flat()
return [
generateRoot(),

View file

@ -262,7 +262,7 @@ export const init = ({
...r,
})),
)
.reduce((acc, arr) => [...acc, ...arr], []),
.flat(),
...inputRuleset,
].map((rule) => {
normalizeCombination(rule)
@ -690,11 +690,11 @@ export const init = ({
.map((combination) => ['normal', ...combination])
.filter((combo) => {
// Optimization: filter out some hard-coded combinations that don't make sense
if (combo.indexOf('disabled') >= 0) {
if (combo.includes('disabled')) {
return !(
combo.indexOf('hover') >= 0 ||
combo.indexOf('focused') >= 0 ||
combo.indexOf('pressed') >= 0
combo.includes('hover') ||
combo.includes('focused') ||
combo.includes('pressed')
)
}
return true
@ -705,13 +705,13 @@ export const init = ({
.map((variant) => {
return stateCombinations.map((state) => ({ variant, state }))
})
.reduce((acc, x) => [...acc, ...x], [])
.flat()
stateVariantCombination.forEach((combination) => {
combination.component = component.name
combination.lazy = component.lazy || parent?.lazy
combination.parent = parent
if (!liteMode && combination.state.indexOf('hover') >= 0) {
if (!liteMode && combination.state.includes('hover')) {
combination.lazy = true
}

View file

@ -47,7 +47,7 @@ const highlightStyle = (prefs) => {
const highlightClass = (user) => {
return (
'USER____' + user.screen_name?.replaceAll('.', '_').replace(/@/g, '_AT_')
'USER____' + user.screen_name?.replaceAll('.', '_').replaceAll('@', '_AT_')
)
}

View file

@ -61,7 +61,7 @@ export const useChatsStore = defineStore('chats', {
addNewChats(chats) {
window.vuex.commit(
'addNewUsers',
chats.map((k) => k.account).filter((k) => k),
chats.map((k) => k.account).filter(Boolean),
)
chats.forEach((updatedChat) => {

View file

@ -120,23 +120,19 @@ export const useEmojiStore = defineStore('emoji', {
}, {})
},
standardEmojiList(state) {
return (
SORTED_EMOJI_GROUP_IDS.map((groupId) =>
(this.emoji[groupId] || []).map((k) =>
injectAnnotations(k, this.unicodeEmojiAnnotations),
),
).reduce((a, b) => a.concat(b), []) ?? []
)
return SORTED_EMOJI_GROUP_IDS.map((groupId) =>
(this.emoji[groupId] || []).map((k) =>
injectAnnotations(k, this.unicodeEmojiAnnotations),
),
).flat()
},
standardEmojiGroupList(state) {
return (
SORTED_EMOJI_GROUP_IDS.map((groupId) => ({
id: groupId,
emojis: (this.emoji[groupId] || []).map((k) =>
injectAnnotations(k, this.unicodeEmojiAnnotations),
),
})) ?? []
)
return SORTED_EMOJI_GROUP_IDS.map((groupId) => ({
id: groupId,
emojis: (this.emoji[groupId] || []).map((k) =>
injectAnnotations(k, this.unicodeEmojiAnnotations),
),
}))
},
},
actions: {

View file

@ -294,7 +294,7 @@ export const useInterfaceStore = defineStore('interface', {
path: 'palettesIndex',
value: { _error: e },
})
return Promise.resolve({})
return {}
}
},
setPalette(value) {
@ -332,7 +332,7 @@ export const useInterfaceStore = defineStore('interface', {
path: 'simple.stylesIndex',
value: { _error: e },
})
return Promise.resolve({})
return {}
}
},
setStyle(value) {
@ -375,7 +375,7 @@ export const useInterfaceStore = defineStore('interface', {
path: 'themesIndex',
value: { _error: e },
})
return Promise.resolve({})
return {}
}
},
setTheme(value) {

View file

@ -104,7 +104,7 @@ const _verifyPrefs = (state) => {
// Simple
Object.entries(defaultState.prefsStorage.simple).forEach(([k, v]) => {
if (typeof v === 'undefined') return
if (v === undefined) return
if (typeof v === 'number' || typeof v === 'boolean') return
if (typeof v === 'object') return
console.warn(
@ -836,7 +836,7 @@ export const useSyncConfigStore = defineStore('sync_config', {
: [path, finalValue]
})
newState.prefsStorage.simple = Object.fromEntries(
newEntries.filter((_) => _),
newEntries.filter(Boolean),
)
return newState
},

View file

@ -43,7 +43,7 @@ const _verifyHighlights = (state) => {
// Simple
Object.entries(defaultState.highlight).forEach(([k, v]) => {
if (typeof v === 'undefined') return
if (v === undefined) return
if (typeof v === 'object') return
console.warn(`User highlight ${k} is invalid type ${typeof v}, unsetting`)
delete state.highlight[k]

View file

@ -10,10 +10,10 @@ const server = require('../../build/dev-server.js')
// For more information on Nightwatch's config file, see
// http://nightwatchjs.org/guide#settings-file
let opts = process.argv.slice(2)
if (opts.indexOf('--config') === -1) {
if (!opts.includes('--config')) {
opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js'])
}
if (opts.indexOf('--env') === -1) {
if (!opts.includes('--env')) {
opts = opts.concat(['--env', 'chrome'])
}

View file

@ -66,10 +66,10 @@ describe('ChatView methods', () => {
it("Doesn't add duplicates", () => {
component.vm.addMessages({ messages: [message1] })
component.vm.addMessages({ messages: [message1] })
expect(component.vm.messages.length).to.eql(1)
expect(component.vm.messages).to.have.length(1)
component.vm.addMessages({ messages: [message2] })
expect(component.vm.messages.length).to.eql(2)
expect(component.vm.messages).to.have.length(2)
})
it('Updates minId and lastMessage and newMessageCount', async () => {
@ -127,11 +127,11 @@ describe('ChatView methods', () => {
})
}
component.vm.cullOlder()
expect(component.vm.messages.length).to.eql(50)
expect(component.vm.messages).to.have.length(50)
expect(component.vm.messages[0].id).to.eql('a0.051')
expect(component.vm.minId).to.eql('a0.051')
expect(component.vm.messages[49].id).to.eql('a0.100')
expect(Object.keys(component.vm.messagesIndex).length).to.eql(50)
expect(Object.keys(component.vm.messagesIndex)).to.have.length(50)
})
})
})

View file

@ -80,8 +80,8 @@ describe('PostStatusForm', () => {
expect(wrapper.vm.refId).to.equal('status-1')
expect(wrapper.vm.quotable).to.equal(true)
expect(wrapper.vm.inReplyToStatusId).to.equal('status-1')
expect(wrapper.vm.newStatus.quote).to.eql(null)
expect(wrapper.vm.newStatus.poll).to.eql(null)
expect(wrapper.vm.newStatus.quote).to.be.null
expect(wrapper.vm.newStatus.poll).to.be.null
expect(wrapper.vm.newStatus.spoilerText).to.eql('')
expect(wrapper.vm.newStatus.mentions).to.eql('@replied')
expect(wrapper.vm.newStatus.status).to.eql('@replied ')
@ -101,8 +101,8 @@ describe('PostStatusForm', () => {
expect(wrapper.vm.statusType).to.equal('reply')
expect(wrapper.vm.isReply).to.equal(true)
expect(wrapper.vm.quotable).to.equal(false)
expect(wrapper.vm.newStatus.quote).to.eql(null)
expect(wrapper.vm.newStatus.poll).to.eql(null)
expect(wrapper.vm.newStatus.quote).to.be.null
expect(wrapper.vm.newStatus.poll).to.be.null
expect(wrapper.vm.newStatus.spoilerText).to.eql('re: subject')
expect(wrapper.vm.newStatus.mentions).to.eql('@replied')
expect(wrapper.vm.newStatus.status).to.eql('@replied ')
@ -114,9 +114,9 @@ describe('PostStatusForm', () => {
expect(wrapper.vm.postingOptions.sensitive).to.eql(false)
expect(wrapper.vm.postingOptions.media).to.eql([])
expect(wrapper.vm.postingOptions.inReplyToStatusId).to.eql('status-2')
expect(wrapper.vm.postingOptions.quoteId).to.eql(null)
expect(wrapper.vm.postingOptions.quoteId).to.be.null
expect(wrapper.vm.postingOptions.contentType).to.eql('text/plain')
expect(wrapper.vm.postingOptions.poll).to.eql(null)
expect(wrapper.vm.postingOptions.poll).to.be.null
})
it('Forces direct mode when replying to a DM, mastodon style subject handling', () => {
@ -139,8 +139,8 @@ describe('PostStatusForm', () => {
expect(wrapper.vm.statusType).to.equal('reply')
expect(wrapper.vm.isReply).to.equal(true)
expect(wrapper.vm.quotable).to.equal(false)
expect(wrapper.vm.newStatus.quote).to.eql(null)
expect(wrapper.vm.newStatus.poll).to.eql(null)
expect(wrapper.vm.newStatus.quote).to.be.null
expect(wrapper.vm.newStatus.poll).to.be.null
expect(wrapper.vm.newStatus.spoilerText).to.eql('subject')
expect(wrapper.vm.newStatus.mentions).to.eql('@replied')
expect(wrapper.vm.newStatus.status).to.eql('@replied ')
@ -207,7 +207,7 @@ describe('PostStatusForm', () => {
wrapper.vm.quoteThreadToggled = true
wrapper.vm.quoteThreadToggled = false
expect(wrapper.vm.newStatus.quote).to.eql(null)
expect(wrapper.vm.newStatus.quote).to.be.null
})
it('Initializes and reset quote when toggling quote attachment', () => {
@ -228,7 +228,7 @@ describe('PostStatusForm', () => {
url: '',
})
wrapper.vm.toggleQuoteForm()
expect(wrapper.vm.newStatus.quote).to.eql(null)
expect(wrapper.vm.newStatus.quote).to.be.null
})
it('Status editing', () => {

View file

@ -187,7 +187,7 @@ describe('piniaPersistPlugin', () => {
const test = useTestStore()
test.$patch({ a: 3 })
expect(await mockStorage.getItem('pinia-local-test')).to.eql(undefined)
expect(await mockStorage.getItem('pinia-local-test')).to.be.undefined
// NOTE: it should not even have tried to save, because the subscribe function
// is called only after loading the initial state.
expect(mockStorage.setItem).not.toHaveBeenCalled()

View file

@ -278,7 +278,7 @@ describe('Statuses module', () => {
timeline: 'public',
})
expect(state.timelines.public.visibleStatuses.length).to.eql(1)
expect(state.timelines.public.visibleStatuses).to.have.length(1)
expect(state.timelines.public.visibleStatuses[0].fave_num).to.eql(1)
expect(state.timelines.public.maxId).to.eq(favorite.id)
@ -289,7 +289,7 @@ describe('Statuses module', () => {
timeline: 'public',
})
expect(state.timelines.public.visibleStatuses.length).to.eql(1)
expect(state.timelines.public.visibleStatuses).to.have.length(1)
expect(state.timelines.public.visibleStatuses[0].fave_num).to.eql(1)
expect(state.timelines.public.maxId).to.eq(favorite.id)
@ -314,7 +314,7 @@ describe('Statuses module', () => {
user,
})
expect(state.timelines.public.visibleStatuses.length).to.eql(1)
expect(state.timelines.public.visibleStatuses).to.have.length(1)
expect(state.timelines.public.visibleStatuses[0].fave_num).to.eql(1)
expect(state.timelines.public.visibleStatuses[0].favorited).to.eql(true)
})
@ -406,7 +406,7 @@ describe('Statuses module', () => {
emoji: '😂',
currentUser: { id: 'me' },
})
expect(state.allStatusesObject['1'].emoji_reactions.length).to.eql(0)
expect(state.allStatusesObject['1'].emoji_reactions).to.have.length(0)
})
})
@ -428,7 +428,7 @@ describe('Statuses module', () => {
state.timelines.public.minId = '5'
mutations.showNewStatuses(state, { timeline: 'public' })
expect(state.timelines.public.visibleStatuses.length).to.eql(2)
expect(state.timelines.public.visibleStatuses).to.have.length(2)
expect(state.timelines.public.minVisibleId).to.equal('10')
expect(state.timelines.public.minId).to.equal('10')
})

View file

@ -68,7 +68,7 @@ describe('The users module', () => {
},
}
const name = 'Guy'
expect(getters.findUser(state)(name)).to.eql(undefined)
expect(getters.findUser(state)(name)).to.be.undefined
})
it('returns user with matching id', () => {
@ -114,7 +114,7 @@ describe('The users module', () => {
},
}
const id = '1'
expect(getters.findUserByName(state)(id)).to.eql(undefined)
expect(getters.findUserByName(state)(id)).to.be.undefined
})
})
})

View file

@ -101,7 +101,7 @@ describe('API Entities normalizer', () => {
describe('Mastoapi preprocessing and converting', () => {
it("doesn't blow up", () => {
const parsed = mastoapidata.map(parseStatus)
expect(parsed.length).to.eq(mastoapidata.length)
expect(parsed).to.have.length(mastoapidata.length)
})
it('processes repeats correctly', () => {

View file

@ -125,7 +125,7 @@ describe('The SyncConfig store', () => {
},
})
expect(store.prefsStorage._journal.length).to.eql(500)
expect(store.prefsStorage._journal).to.have.length(500)
})
it('should reset local timestamp to remote if contents are the same', async () => {
@ -173,7 +173,7 @@ describe('The SyncConfig store', () => {
}
store.setPreference({ path: 'simple.palette', value: '1' })
expect(store.prefsStorage.simple.palette).to.eql('1')
expect(store.prefsStorage._journal.length).to.eql(1)
expect(store.prefsStorage._journal).to.have.length(1)
expect(store.prefsStorage._journal[0]).to.eql({
path: 'simple.palette',
operation: 'set',
@ -199,7 +199,7 @@ describe('The SyncConfig store', () => {
store.updateCache({ username: 'test' })
expect(store.prefsStorage.simple.palette).to.eql(2)
expect(store.prefsStorage.collections.palette).to.eql([])
expect(store.prefsStorage._journal.length).to.eql(2)
expect(store.prefsStorage._journal).to.have.length(2)
expect(store.prefsStorage._journal[0]).to.eql({
path: 'simple.palette',
operation: 'set',
@ -229,7 +229,7 @@ describe('The SyncConfig store', () => {
store.updateCache({ username: 'test' })
expect(store.prefsStorage.simple.palette).to.eql(1)
expect(store.prefsStorage.collections.palette).to.eql([2])
expect(store.prefsStorage._journal.length).to.eql(2)
expect(store.prefsStorage._journal).to.have.length(2)
})
// TODO We need a proper test for object-based stores
@ -245,7 +245,7 @@ describe('The SyncConfig store', () => {
expect(store.prefsStorage.simple.fontInput).to.not.have.property(
'family',
)
expect(store.prefsStorage._journal.length).to.eql(1)
expect(store.prefsStorage._journal).to.have.length(1)
})
it('should not allow unsetting depth <= 2', () => {

View file

@ -55,7 +55,7 @@ describe('The UserHighlight store', () => {
user: 'highlight@testing',
type: 'test',
})
expect(store.highlight._journal.length).to.eql(1)
expect(store.highlight._journal).to.have.length(1)
expect(store.highlight._journal[0]).to.eql({
user: 'highlight@testing',
operation: 'set',
@ -74,7 +74,7 @@ describe('The UserHighlight store', () => {
user: 'highlight@testing.xyz',
type: 'test',
})
expect(store.highlight._journal.length).to.eql(1)
expect(store.highlight._journal).to.have.length(1)
expect(store.highlight._journal[0]).to.eql({
user: 'highlight@testing.xyz',
operation: 'set',
@ -98,7 +98,7 @@ describe('The UserHighlight store', () => {
user: 'a@test.xyz',
type: 'foo',
})
expect(store.highlight._journal.length).to.eql(1)
expect(store.highlight._journal).to.have.length(1)
})
})
})