Merge branch 'sonarqube-cleanup' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2026-08-04 16:38:47 +03:00
commit 99ee170582
66 changed files with 275 additions and 343 deletions

View file

@ -1,41 +0,0 @@
import chalk from 'chalk'
import semver from 'semver'
import packageConfig from '../package.json' with { type: 'json' }
var versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node,
},
]
export default function () {
const warnings = []
for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(
mod.name +
': ' +
chalk.red(mod.currentVersion) +
' should be ' +
chalk.green(mod.versionRequirement),
)
}
}
if (warnings.length) {
console.warn(
chalk.yellow(
'\nTo use this template, you must update following to modules:\n',
),
)
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i]
console.warn(' ' + warning)
}
process.exit(1)
}
}

View file

@ -1,8 +1,8 @@
import childProcess from 'child_process' import childProcess from 'node:child_process'
export const getCommitHash = () => { export const getCommitHash = () => {
const subst = '$Format:%h$' const subst = '$Format:%h$'
if (!subst.match(/Format:/)) { if (!/Format:/.exec(subst)) {
return subst return subst
} else { } else {
try { try {

View file

@ -31,7 +31,6 @@ export const buildSwPlugin = ({ swSrc, swDest }) => {
name: 'build-sw-plugin', name: 'build-sw-plugin',
enforce: 'post', enforce: 'post',
configResolved(resolvedConfig) { configResolved(resolvedConfig) {
resolvedConfig
config = { config = {
define: resolvedConfig.define, define: resolvedConfig.define,
resolve: resolvedConfig.resolve, resolve: resolvedConfig.resolve,
@ -60,7 +59,7 @@ export const buildSwPlugin = ({ swSrc, swDest }) => {
sequential: true, sequential: true,
async handler(_, bundle) { async handler(_, bundle) {
const assets = Object.keys(bundle) const assets = Object.keys(bundle)
.filter((name) => !/\.map$/.test(name)) .filter((name) => !name.endsWith('.map'))
.map((name) => '/' + name) .map((name) => '/' + name)
config.plugins.push({ config.plugins.push({

View file

@ -1,10 +1,10 @@
import fs from 'node:fs'
import emojis from '@kazvmoe-infra/unicode-emoji-json/data-by-group.json' with { import emojis from '@kazvmoe-infra/unicode-emoji-json/data-by-group.json' with {
type: 'json', type: 'json',
} }
import fs from 'fs'
Object.keys(emojis).map((k) => { Object.keys(emojis).map((k) => {
emojis[k].map((e) => { emojis[k].forEach((e) => {
delete e.unicode_version delete e.unicode_version
delete e.emoji_version delete e.emoji_version
delete e.skin_tone_support_unicode_version delete e.skin_tone_support_unicode_version
@ -12,11 +12,15 @@ Object.keys(emojis).map((k) => {
}) })
const res = {} const res = {}
Object.keys(emojis).map((k) => { Object.keys(emojis).forEach((k) => {
const groupId = k.replace('&', 'and').replace(/ /g, '-').toLowerCase() const groupId = k.replace('&', 'and').replaceAll(' ', '-').toLowerCase()
res[groupId] = emojis[k] res[groupId] = emojis[k]
}) })
console.info('Updating emojis...') console.info('Updating emojis...')
fs.writeFileSync('src/assets/emoji.json', JSON.stringify(res)) try {
console.info('Done.') fs.writeFileSync('src/assets/emoji.json', JSON.stringify(res))
console.info('Done.')
} catch (e) {
console.error('Failed updating emoji', e)
}

View file

@ -1,15 +1,19 @@
FROM mcr.microsoft.com/playwright:v1.61.0-jammy FROM mcr.microsoft.com/playwright:v1.61.0-jammy
RUN npm install -g yarn@1.22.22
RUN adduser --system playwright --group --shell=/bin/bash
USER playwright
WORKDIR /app WORKDIR /app
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
RUN npm install -g yarn@1.22.22
COPY package.json yarn.lock ./ COPY package.json yarn.lock ./
RUN yarn --frozen-lockfile RUN yarn --frozen-lockfile
COPY . . COPY --chown=playwright ./build ./src ./test ./public ./static ./yarn.lock ./package.json .
ENV CI=1 ENV CI=1

View file

@ -31,7 +31,7 @@
<div class="chunk" id="chunk-E"> <div class="chunk" id="chunk-E">
</div> </div>
</div> </div>
<img id="mascot" src="/static/pleromatan_apology_small.webp"> <img id="mascot" alt="A cute mascot" src="/static/pleromatan_apology_small.webp">
</div> </div>
<div id="status" class="css-ok"> <div id="status" class="css-ok">
<!-- (。><) --> <!-- (。><) -->

View file

@ -6,4 +6,4 @@
Pleroma install containing the real ToS for your instance.</p> Pleroma install containing the real ToS for your instance.</p>
<p>See the <a href='https://docs.pleroma.social/backend/configuration/static_dir/'>Pleroma documentation</a> for more information.</p> <p>See the <a href='https://docs.pleroma.social/backend/configuration/static_dir/'>Pleroma documentation</a> for more information.</p>
<br> <br>
<img src="/static/logo.svg" style="display: block; margin: auto; max-width: 100%; height: 50px; object-fit: contain;" /> <img src="/static/logo.svg" alt="Pleroma Logo" style="display: block; margin: auto; max-width: 100%; height: 50px; object-fit: contain;" />

View file

@ -1,10 +1,11 @@
// stylelint-disable rscss/class-format
/* stylelint-disable no-descending-specificity */
@use "panel"; @use "panel";
@import '@fortawesome/fontawesome-svg-core/styles.css'; @import '@fortawesome/fontawesome-svg-core/styles.css';
@import '@kazvmoe-infra/pinch-zoom-element/dist/pinch-zoom.css'; @import '@kazvmoe-infra/pinch-zoom-element/dist/pinch-zoom.css';
// stylelint-disable rscss/class-format
/* stylelint-disable no-descending-specificity */
:root { :root {
--status-margin: 0.75em; --status-margin: 0.75em;
--post-line-height: 1.4; --post-line-height: 1.4;
@ -934,7 +935,6 @@ option {
#splash { #splash {
pointer-events: none; pointer-events: none;
// transition: opacity 0.5s;
#status { #status {
&.css-ok { &.css-ok {

View file

@ -39,7 +39,7 @@ const USERS_URL_LIST = ({
isAdmin && 'is_admin', isAdmin && 'is_admin',
isModerator && 'is_moderator', isModerator && 'is_moderator',
] ]
.filter((x) => x) .filter(Boolean)
.join(',') .join(',')
return `/api/v1/pleroma/admin/users?page=${page}&page_size=${pageSize}&filters=${filters_str}&query=${query}&name=${name}&email=${email}` return `/api/v1/pleroma/admin/users?page=${page}&page_size=${pageSize}&filters=${filters_str}&query=${query}&name=${name}&email=${email}`
} }
@ -236,7 +236,7 @@ export const changeStatusScope = ({
opts: { id, sensitive, visibility }, opts: { id, sensitive, visibility },
credentials, credentials,
}) => { }) => {
var payload = {} const payload = {}
if (typeof sensitive !== 'undefined') { if (typeof sensitive !== 'undefined') {
payload['sensitive'] = sensitive payload['sensitive'] = sensitive
} }

View file

@ -6,12 +6,12 @@ export const paramsString = (params = {}) => {
if (params == null || params === undefined) return '' if (params == null || params === undefined) return ''
if (typeof params !== 'object' || Array.isArray(params)) { if (typeof params !== 'object' || Array.isArray(params)) {
throw new Error('Params are not an object!') throw new TypeError('Params are not an object!')
} }
const entries = (() => { const entries = (() => {
if (params instanceof Map) { if (params instanceof Map) {
return params.entries() return [...params.entries()]
} else { } else {
return Object.entries(params) return Object.entries(params)
} }
@ -26,7 +26,7 @@ export const paramsString = (params = {}) => {
(typeof v === 'object' && !Array.isArray(v)) || (typeof v === 'object' && !Array.isArray(v)) ||
typeof v === 'function' typeof v === 'function'
) { ) {
throw new Error('Param cannot be non-primitive!') throw new TypeError('Param cannot be non-primitive!')
} }
if (Array.isArray(v)) { if (Array.isArray(v)) {
arrays.push([k, v]) arrays.push([k, v])
@ -42,7 +42,7 @@ export const paramsString = (params = {}) => {
typeof v === 'function' || typeof v === 'function' ||
typeof v === 'undefined' typeof v === 'undefined'
) )
throw new Error('Array param cannot contain non-primitives!') throw new TypeError('Array param cannot contain non-primitives!')
}) })
}) })
@ -109,7 +109,9 @@ export const promisedRequest = async ({
.get('content-type') .get('content-type')
.split(';') .split(';')
.map((x) => x.toLowerCase().trim()) .map((x) => x.toLowerCase().trim())
const contentLength = parseInt(response.headers.get('content-length')) const contentLength = Number.parseInt(
response.headers.get('content-length'),
)
if (contentLength === 0) return null if (contentLength === 0) return null
switch (contentType) { switch (contentType) {

View file

@ -105,7 +105,7 @@ export const fetchUserByName = ({ name, credentials }) =>
}) })
.then(({ data }) => data.id) .then(({ data }) => data.id)
.catch((error) => { .catch((error) => {
if (error && error.statusCode === 404) { if (error?.statusCode === 404) {
// Either the backend does not support lookup endpoint, // Either the backend does not support lookup endpoint,
// or there is no user with such name. Fallback and treat name as id. // or there is no user with such name. Fallback and treat name as id.
return name return name

View file

@ -1,4 +1,4 @@
import { concat, last } from 'lodash' import { last } from 'lodash'
import { paramsString, promisedRequest } from './helpers.js' import { paramsString, promisedRequest } from './helpers.js'
import { fetchFriends, MASTODON_STATUS_URL } from './public.js' import { fetchFriends, MASTODON_STATUS_URL } from './public.js'
@ -220,7 +220,7 @@ export const postStatus = ({
}) })
if (pollOptions.some((option) => option !== '')) { if (pollOptions.some((option) => option !== '')) {
const normalizedPoll = { const normalizedPoll = {
expires_in: parseInt(poll.expiresIn, 10), expires_in: Number.parseInt(poll.expiresIn, 10),
multiple: poll.multiple, multiple: poll.multiple,
} }
Object.keys(normalizedPoll).forEach((key) => { Object.keys(normalizedPoll).forEach((key) => {
@ -278,7 +278,7 @@ export const editStatus = ({
if (pollOptions.some((option) => option !== '')) { if (pollOptions.some((option) => option !== '')) {
const normalizedPoll = { const normalizedPoll = {
expires_in: parseInt(poll.expiresIn, 10), expires_in: Number.parseInt(poll.expiresIn, 10),
multiple: poll.multiple, multiple: poll.multiple,
} }
Object.keys(normalizedPoll).forEach((key) => { Object.keys(normalizedPoll).forEach((key) => {
@ -412,7 +412,7 @@ export const exportFriends = ({ id, credentials }) => {
credentials, credentials,
withRelationships: true, withRelationships: true,
}) })
friends = concat(friends, users) friends = [...friends, ...users]
if (users.length === 0) { if (users.length === 0) {
more = false more = false
} }
@ -613,7 +613,7 @@ export const listAliases = ({ credentials }) =>
method: 'GET', method: 'GET',
credentials, credentials,
params: { params: {
_cacheBooster: new Date().getTime(), _cacheBooster: Date().now(),
}, },
}) })
@ -799,7 +799,7 @@ export const listBackups = ({ credentials }) =>
method: 'GET', method: 'GET',
credentials, credentials,
params: { params: {
_cacheBooster: new Date().getTime(), _cacheBooster: Date().now(),
}, },
}) })

View file

@ -141,13 +141,11 @@ export const handleMastoWS = (
if (data.result === 'success') { if (data.result === 'success') {
console.debug('[WS] Successfully authenticated') console.debug('[WS] Successfully authenticated')
onAuthenticated() onAuthenticated()
} else if (data.error === 'already_authenticated') {
onAuthenticated()
} else { } else {
if (data.error === 'already_authenticated') { console.error('[WS] Unable to authenticate:', data.error)
onAuthenticated() wsEvent.target.close()
} else {
console.error('[WS] Unable to authenticate:', data.error)
wsEvent.target.close()
}
} }
} }
return null return null

View file

@ -63,14 +63,14 @@ const parsedInitialResults = () => {
const decodeUTF8Base64 = (data) => { const decodeUTF8Base64 = (data) => {
const rawData = atob(data) const rawData = atob(data)
const array = Uint8Array.from([...rawData].map((char) => char.charCodeAt(0))) const array = Uint8Array.from([...rawData].map((char) => char.codePointAt(0)))
const text = new TextDecoder().decode(array) const text = new TextDecoder().decode(array)
return text return text
} }
const preloadFetch = async (request) => { const preloadFetch = async (request) => {
const data = parsedInitialResults() const data = parsedInitialResults()
if (!data || !data[request]) { if (!data?.[request]) {
return window.fetch(request) return window.fetch(request)
} }
const decoded = decodeUTF8Base64(data[request]) const decoded = decodeUTF8Base64(data[request])
@ -170,9 +170,9 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
let config = {} let config = {}
if (overrides.staticConfigPreference && env === 'development') { if (overrides.staticConfigPreference && env === 'development') {
console.warn('OVERRIDING API CONFIG WITH STATIC CONFIG') console.warn('OVERRIDING API CONFIG WITH STATIC CONFIG')
config = Object.assign({}, apiConfig, staticConfig) config = { ...apiConfig, ...staticConfig }
} else { } else {
config = Object.assign({}, staticConfig, apiConfig) config = { ...staticConfig, ...apiConfig }
} }
Object.keys(INSTANCE_IDENTITY_DEFAULT_DEFINITIONS).forEach((source) => { Object.keys(INSTANCE_IDENTITY_DEFAULT_DEFINITIONS).forEach((source) => {
@ -353,19 +353,19 @@ const getNodeInfo = async ({ store }) => {
const uploadLimits = metadata.uploadLimits const uploadLimits = metadata.uploadLimits
useInstanceStore().set({ useInstanceStore().set({
path: 'limits.uploadlimit', path: 'limits.uploadlimit',
value: parseInt(uploadLimits.general), value: Number.parseInt(uploadLimits.general),
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'limits.avatarlimit', path: 'limits.avatarlimit',
value: parseInt(uploadLimits.avatar), value: Number.parseInt(uploadLimits.avatar),
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'limits.backgroundlimit', path: 'limits.backgroundlimit',
value: parseInt(uploadLimits.background), value: Number.parseInt(uploadLimits.background),
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'limits.bannerlimit', path: 'limits.bannerlimit',
value: parseInt(uploadLimits.banner), value: Number.parseInt(uploadLimits.banner),
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'limits.fieldsLimits', path: 'limits.fieldsLimits',
@ -409,7 +409,7 @@ const getNodeInfo = async ({ store }) => {
useInstanceCapabilitiesStore().set( useInstanceCapabilitiesStore().set(
'tagPolicyAvailable', 'tagPolicyAvailable',
typeof federation.mrf_policies === 'undefined' federation.mrf_policies === undefined
? false ? false
: metadata.federation.mrf_policies.includes('TagPolicy'), : metadata.federation.mrf_policies.includes('TagPolicy'),
) )
@ -420,8 +420,7 @@ const getNodeInfo = async ({ store }) => {
}) })
useInstanceStore().set({ useInstanceStore().set({
path: 'federating', path: 'federating',
value: value: federation.enabled === undefined ? true : federation.enabled,
typeof federation.enabled === 'undefined' ? true : federation.enabled,
}) })
const accountActivationRequired = metadata.accountActivationRequired const accountActivationRequired = metadata.accountActivationRequired
@ -443,7 +442,7 @@ const getNodeInfo = async ({ store }) => {
const setConfig = async ({ store }) => { const setConfig = async ({ store }) => {
// apiConfig, staticConfig // apiConfig, staticConfig
const configInfos = await Promise.all([ const configInfos = await Promise.all([
getBackendProvidedConfig({ store }), getBackendProvidedConfig(),
getStaticConfig(), getStaticConfig(),
]) ])
const apiConfig = configInfos[0] const apiConfig = configInfos[0]
@ -457,7 +456,7 @@ const checkOAuthToken = async ({ store }) => {
if (oauth.userToken) { if (oauth.userToken) {
return store.dispatch('loginUser', oauth.userToken) return store.dispatch('loginUser', oauth.userToken)
} }
return Promise.resolve() return
} }
const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => { const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
@ -485,7 +484,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
// do some checks to avoid common errors // do some checks to avoid common errors
if (!Object.keys(allStores).length) { if (!Object.keys(allStores).length) {
throw new Error( throw new TypeError(
'No stores are available. Check the code in src/boot/after_store.js', 'No stores are available. Check the code in src/boot/after_store.js',
) )
} }
@ -495,7 +494,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
const isStoreName = (name) => name.startsWith('use') const isStoreName = (name) => name.startsWith('use')
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
if (Object.keys(mod).filter(isStoreName).length !== 1) { if (Object.keys(mod).filter(isStoreName).length !== 1) {
throw new Error( throw new TypeError(
'Each store file must export exactly one store as a named export. Check your code in src/stores/', 'Each store file must export exactly one store as a named export. Check your code in src/stores/',
) )
} }
@ -504,13 +503,13 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
if (storeFuncName && typeof mod[storeFuncName] === 'function') { if (storeFuncName && typeof mod[storeFuncName] === 'function') {
const p = mod[storeFuncName]().$persistLoaded const p = mod[storeFuncName]().$persistLoaded
if (!(p instanceof Promise)) { if (!(p instanceof Promise)) {
throw new Error( throw new TypeError(
`${name} store's $persistLoaded is not a Promise. The persist plugin is not applied.`, `${name} store's $persistLoaded is not a Promise. The persist plugin is not applied.`,
) )
} }
await p await p
} else { } else {
throw new Error( throw new TypeError(
`Store module ${name} does not export a 'use...' function`, `Store module ${name} does not export a 'use...' function`,
) )
} }
@ -518,14 +517,15 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
) )
} }
let newStorageError
try { try {
await waitForAllStoresToLoad() await waitForAllStoresToLoad()
} catch (e) { } catch (e) {
console.error('Cannot load stores:', e) console.error('Cannot load stores:', e)
storageError = e newStorageError = e
} }
if (storageError) { if (storageError || newStorageError) {
useInterfaceStore().pushGlobalNotice({ useInterfaceStore().pushGlobalNotice({
messageKey: 'errors.storage_unavailable', messageKey: 'errors.storage_unavailable',
level: 'error', level: 'error',
@ -547,9 +547,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
const overrides = window.___pleromafe_dev_overrides || {} const overrides = window.___pleromafe_dev_overrides || {}
const server = const server =
typeof overrides.target !== 'undefined' overrides.target !== undefined ? overrides.target : window.location.origin
? overrides.target
: window.location.origin
useInstanceStore().set({ path: 'server', value: server }) useInstanceStore().set({ path: 'server', value: server })
await setConfig({ store }) await setConfig({ store })
@ -561,7 +559,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
}) })
} catch (e) { } catch (e) {
window.splashError(e) window.splashError(e)
return Promise.reject(e) throw e
} }
applyStyleConfig(useMergedConfigStore().mergedConfig, i18n.global) applyStyleConfig(useMergedConfigStore().mergedConfig, i18n.global)
@ -573,7 +571,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
getInstancePanel({ store }), getInstancePanel({ store }),
getNodeInfo({ store }), getNodeInfo({ store }),
getInstanceConfig({ store }), getInstanceConfig({ store }),
]).catch((e) => Promise.reject(e)) ])
getTOS({ store }) getTOS({ store })
getStickers({ store }) getStickers({ store })
@ -583,7 +581,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
routes: routes(store), routes: routes(store),
scrollBehavior: (to, _from, savedPosition) => { scrollBehavior: (to, _from, savedPosition) => {
if (to.matched.some((m) => m.meta.dontScroll)) { if (to.matched.some((m) => m.meta.dontScroll)) {
return false return {}
} }
return savedPosition || { left: 0, top: 0 } return savedPosition || { left: 0, top: 0 }
}, },

View file

@ -39,7 +39,7 @@ const ChatListItem = {
messageForStatusContent() { messageForStatusContent() {
const message = this.chat.lastMessage const message = this.chat.lastMessage
const messageEmojis = message ? message.emojis : [] const messageEmojis = message ? message.emojis : []
const isYou = message && message.account_id === this.currentUser.id const isYou = message?.account_id === this.currentUser.id
const content = message ? this.attachmentInfo || message.content : '' const content = message ? this.attachmentInfo || message.content : ''
const messagePreview = isYou const messagePreview = isYou
? `<i>${this.$t('chats.you')}</i> ${content}` ? `<i>${this.$t('chats.you')}</i> ${content}`

View file

@ -111,7 +111,7 @@ const ChatMessage = {
const user = this.$store.getters.findUser( const user = this.$store.getters.findUser(
this.message.in_reply_to_user_id, this.message.in_reply_to_user_id,
) )
return user && user.screen_name_ui return user?.screen_name_ui
} }
}, },
replyProfileLink() { replyProfileLink() {

View file

@ -53,7 +53,7 @@
:user-screen-name="message.in_reply_to_screen_name" :user-screen-name="message.in_reply_to_screen_name"
/> />
<!-- v-if is there because status might not be loaded yet --> <!-- v-if is there because status might not be loaded yet -->
<template v-if="customReplyTo && customReplyTo.text.trim().length > 0"> <template v-if="customReplyTo?.text.trim().length > 0">
: :
<StatusBody <StatusBody
class="reply-body faint" class="reply-body faint"

View file

@ -16,7 +16,7 @@
<RichContent <RichContent
v-if="user" v-if="user"
class="username" class="username"
:title="'@'+(user && user.screen_name_ui)" :title="'@'+(user?.screen_name_ui)"
:html="htmlTitle" :html="htmlTitle"
:emoji="user.emoji || []" :emoji="user.emoji || []"
:allow-non-square-emoji="allowNonSquareEmoji" :allow-non-square-emoji="allowNonSquareEmoji"

View file

@ -134,7 +134,7 @@ export default {
emits: ['update:modelValue'], emits: ['update:modelValue'],
computed: { computed: {
present() { present() {
return typeof this.modelValue !== 'undefined' return this.modelValue !== undefined
}, },
validColor() { validColor() {
return hex2rgb(this.modelValue || this.fallback) return hex2rgb(this.modelValue || this.fallback)

View file

@ -73,17 +73,15 @@ export default {
} }
}, },
logoBgStyle() { logoBgStyle() {
return Object.assign( const mask = this.enableMask
{ ? {}
margin: `${this.logoMargin} 0`, : { 'background-color': this.enableMask ? '' : 'transparent' }
opacity: this.searchBarHidden ? 1 : 0,
}, return {
this.enableMask margin: `${this.logoMargin} 0`,
? {} opacity: this.searchBarHidden ? 1 : 0,
: { ...mask,
'background-color': this.enableMask ? '' : 'transparent', }
},
)
}, },
...mapState(useInstanceStore, ['privateMode']), ...mapState(useInstanceStore, ['privateMode']),
...mapState(useInstanceStore, { ...mapState(useInstanceStore, {

View file

@ -50,7 +50,7 @@
/> />
</button> </button>
<button <button
v-if="currentUser && currentUser.role === 'admin'" v-if="currentUser?.role === 'admin'"
class="button-unstyled nav-icon" class="button-unstyled nav-icon"
target="_blank" target="_blank"
:title="$t('nav.administration')" :title="$t('nav.administration')"

View file

@ -29,7 +29,7 @@ const FollowRequestCard = {
notif.from_profile.id === this.user.id && notif.from_profile.id === this.user.id &&
notif.type === 'follow_request', notif.type === 'follow_request',
) )
return notif && notif.id return notif?.id
}, },
showApproveConfirmDialog() { showApproveConfirmDialog() {
this.showingApproveConfirmDialog = true this.showingApproveConfirmDialog = true

View file

@ -42,7 +42,7 @@ export default {
emits: ['update:modelValue'], emits: ['update:modelValue'],
computed: { computed: {
present() { present() {
return typeof this.modelValue !== 'undefined' return this.modelValue !== undefined
}, },
}, },
} }

View file

@ -89,7 +89,7 @@ export default {
this.error = false this.error = false
const notice = this.noticeRegex.exec(value) const notice = this.noticeRegex.exec(value)
if (notice && notice.length === 4) { if (notice?.length === 4) {
this.$emit('update:id', notice[3]) this.$emit('update:id', notice[3])
} else if (value) { } else if (value) {
this.loading = true this.loading = true
@ -102,7 +102,7 @@ export default {
type: 'statuses', type: 'statuses',
}) })
.then((data) => { .then((data) => {
if (data && data.statuses && data.statuses.length === 1) { if (data?.statuses && data.statuses.length === 1) {
this.$emit('update:id', data.statuses[0].id) this.$emit('update:id', data.statuses[0].id)
} else { } else {
this.handleError(true) this.handleError(true)

View file

@ -68,7 +68,7 @@ export default {
emits: ['update:modelValue'], emits: ['update:modelValue'],
computed: { computed: {
present() { present() {
return typeof this.modelValue !== 'undefined' return this.modelValue !== undefined
}, },
}, },
} }

View file

@ -335,7 +335,7 @@ export default {
this.pauseMfm ? '-pause' : '', this.pauseMfm ? '-pause' : '',
this.scaleMfm ? '-scale' : '', this.scaleMfm ? '-scale' : '',
] ]
.filter((x) => x) .filter(Boolean)
.join(' ') .join(' ')
newAttrs['data-mfm-operator'] = mfmOperator newAttrs['data-mfm-operator'] = mfmOperator
switch (mfmOperator) { switch (mfmOperator) {

View file

@ -42,7 +42,7 @@ export default {
emits: ['update:modelValue'], emits: ['update:modelValue'],
computed: { computed: {
present() { present() {
return typeof this.modelValue !== 'undefined' return this.modelValue !== undefined
}, },
}, },
} }

View file

@ -374,7 +374,7 @@
class="emoji-list setting-list" class="emoji-list setting-list"
> >
<EmojiEditingPopover <EmojiEditingPopover
v-if="pack && pack.remote === undefined" v-if="pack?.remote === undefined"
class="emoji-item" class="emoji-item"
placement="bottom" placement="bottom"
new-upload new-upload

View file

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

View file

@ -159,7 +159,7 @@ export default {
return this.source || this.defaultSource return this.source || this.defaultSource
}, },
realDraftMode() { realDraftMode() {
return typeof this.draftMode === 'undefined' return this.draftMode === undefined
? this.defaultDraftMode ? this.defaultDraftMode
: this.draftMode : this.draftMode
}, },

View file

@ -47,7 +47,7 @@ export default {
// In case of controlled component // In case of controlled component
if (this.activeTab) { if (this.activeTab) {
return this.slots().findIndex( return this.slots().findIndex(
(slot) => slot && slot.props && this.activeTab === slot.props.key, (slot) => slot?.props && this.activeTab === slot.props.key,
) )
} else { } else {
return this.active return this.active

View file

@ -236,7 +236,7 @@ const AppearanceTab = {
}, },
stylePalettes() { stylePalettes() {
const ruleset = useInterfaceStore().styleDataUsed || [] const ruleset = useInterfaceStore().styleDataUsed || []
if (!ruleset && ruleset.length === 0) return if (!ruleset?.length === 0) return
const meta = ruleset.find((x) => x.component === '@meta') const meta = ruleset.find((x) => x.component === '@meta')
const result = ruleset const result = ruleset
.filter((x) => x.component.startsWith('@palette')) .filter((x) => x.component.startsWith('@palette'))
@ -401,7 +401,7 @@ const AppearanceTab = {
} }
theme3 = init({ theme3 = init({
inputRuleset: [...input, paletteRule].filter((x) => x), inputRuleset: [...input, paletteRule].filter(Boolean),
ultimateBackgroundColor: '#000000', ultimateBackgroundColor: '#000000',
liteMode: true, liteMode: true,
onlyNormalState: true, onlyNormalState: true,

View file

@ -95,7 +95,7 @@ const DataImportExportTab = {
return users return users
.map((user) => { .map((user) => {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user?.is_local) {
// append the instance address // append the instance address
return user.screen_name + '@' + location.hostname return user.screen_name + '@' + location.hostname
} }

View file

@ -81,7 +81,7 @@ const MutesAndBlocks = {
return users return users
.map((user) => { .map((user) => {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user?.is_local) {
// append the instance address // append the instance address
return user.screen_name + '@' + location.hostname return user.screen_name + '@' + location.hostname
} }

View file

@ -147,7 +147,7 @@ export default {
}) })
}, },
mounted() { mounted() {
if (typeof this.shadowSelected === 'undefined') { if (this.shadowSelected === undefined) {
this.shadowSelected = this.shadowsAvailable[0] this.shadowSelected = this.shadowsAvailable[0]
} }
}, },
@ -633,17 +633,11 @@ export default {
if (version === 0) { if (version === 0) {
if (input.version) version = input.version if (input.version) version = input.version
// Old v1 naming: fg is text, btn is foreground // Old v1 naming: fg is text, btn is foreground
if ( if (colors.text === undefined && colors.fg !== undefined) {
typeof colors.text === 'undefined' &&
typeof colors.fg !== 'undefined'
) {
version = 1 version = 1
} }
// New v2 naming: text is text, fg is foreground // New v2 naming: text is text, fg is foreground
if ( if (colors.text !== undefined && colors.fg !== undefined) {
typeof colors.text !== 'undefined' &&
typeof colors.fg !== 'undefined'
) {
version = 2 version = 2
} }
} }
@ -679,7 +673,7 @@ export default {
if (opacity && !this.keepOpacity) { if (opacity && !this.keepOpacity) {
this.clearOpacity() this.clearOpacity()
Object.entries(opacity).forEach(([k, v]) => { Object.entries(opacity).forEach(([k, v]) => {
if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return if (v === undefined || v === null || Number.isNaN(v)) return
this[k + 'OpacityLocal'] = v this[k + 'OpacityLocal'] = v
}) })
} }

View file

@ -602,7 +602,7 @@ export default {
.map((x) => Object.entries(x.directives)) .map((x) => Object.entries(x.directives))
.flat() .flat()
}) })
.filter((x) => x) .filter(Boolean)
.flat() .flat()
.map(([name, value]) => { .map(([name, value]) => {
const [valType, valVal] = value.split('|') const [valType, valVal] = value.split('|')

View file

@ -220,7 +220,7 @@
</router-link> </router-link>
</li> </li>
<li <li
v-if="currentUser && currentUser.role === 'admin'" v-if="currentUser?.role === 'admin'"
@click="toggleDrawer" @click="toggleDrawer"
> >
<button <button

View file

@ -316,11 +316,11 @@ const Status = {
return ( return (
(status.muted && !status.thread_muted) || (status.muted && !status.thread_muted) ||
// Reprööt of a muted post according to BE // Reprööt of a muted post according to BE
(reblog && reblog.muted && !reblog.thread_muted) || (reblog?.muted && !reblog.thread_muted) ||
// Muted user // Muted user
relationship.muting || relationship.muting ||
// Muted user of a reprööt // Muted user of a reprööt
(relationshipReblog && relationshipReblog.muting) relationshipReblog?.muting
) )
}, },
shouldNotMute() { shouldNotMute() {
@ -333,7 +333,7 @@ const Status = {
// Don't mute user's posts on user timeline (except reblogs) // Don't mute user's posts on user timeline (except reblogs)
((!reblog && status.user.id === this.profileUserId) || ((!reblog && status.user.id === this.profileUserId) ||
// Same as above but also allow self-reblogs // Same as above but also allow self-reblogs
(reblog && reblog.user.id === this.profileUserId))) || reblog?.user.id === this.profileUserId)) ||
// Don't mute statuses in muted conversation when said conversation is opened // Don't mute statuses in muted conversation when said conversation is opened
(this.inConversation && status.thread_muted)) && (this.inConversation && status.thread_muted)) &&
// No excuses if post has muted words // No excuses if post has muted words
@ -374,7 +374,7 @@ const Status = {
const user = this.$store.getters.findUser( const user = this.$store.getters.findUser(
this.status.in_reply_to_user_id, this.status.in_reply_to_user_id,
) )
return user && user.screen_name_ui return user?.screen_name_ui
} }
}, },
combinedFavsAndRepeatsUsers() { combinedFavsAndRepeatsUsers() {

View file

@ -225,7 +225,7 @@
/> />
</button> </button>
<button <button
v-if="inThreadForest && replies && replies.length && !simpleTree" v-if="inThreadForest && replies?.length && !simpleTree"
class="button-unstyled" class="button-unstyled"
:title="threadShowing ? $t('status.thread_hide') : $t('status.thread_show')" :title="threadShowing ? $t('status.thread_hide') : $t('status.thread_show')"
:aria-expanded="threadShowing ? 'true' : 'false'" :aria-expanded="threadShowing ? 'true' : 'false'"
@ -426,7 +426,7 @@
/> />
<div <div
v-if="inConversation && !isPreview && replies && replies.length" v-if="inConversation && !isPreview && replies?.length"
class="replies" class="replies"
> >
<button <button

View file

@ -138,7 +138,7 @@ export default {
const existingReaction = this.status.emoji_reactions.find( const existingReaction = this.status.emoji_reactions.find(
(r) => r.name === emoji, (r) => r.name === emoji,
) )
if (existingReaction && existingReaction.me) { if (existingReaction?.me) {
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji }) this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
} else { } else {
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })

View file

@ -47,7 +47,7 @@ export default {
// In case of controlled component // In case of controlled component
if (this.activeTab) { if (this.activeTab) {
return this.slots().findIndex( return this.slots().findIndex(
(slot) => slot && slot.props && this.activeTab === slot.props.key, (slot) => slot?.props && this.activeTab === slot.props.key,
) )
} else { } else {
return this.active return this.active

View file

@ -154,7 +154,7 @@ const Timeline = {
}) })
}, },
mounted() { mounted() {
if (typeof document.hidden !== 'undefined') { if (document.hidden !== undefined) {
document.addEventListener( document.addEventListener(
'visibilitychange', 'visibilitychange',
this.handleVisibilityChange, this.handleVisibilityChange,
@ -168,7 +168,7 @@ const Timeline = {
unmounted() { unmounted() {
window.removeEventListener('scroll', this.handleScroll) window.removeEventListener('scroll', this.handleScroll)
window.removeEventListener('keydown', this.handleShortKey) window.removeEventListener('keydown', this.handleShortKey)
if (typeof document.hidden !== 'undefined') if (document.hidden !== undefined)
document.removeEventListener( document.removeEventListener(
'visibilitychange', 'visibilitychange',
this.handleVisibilityChange, this.handleVisibilityChange,
@ -231,7 +231,7 @@ const Timeline = {
tag: this.tag, tag: this.tag,
}) })
.then(({ statuses }) => { .then(({ statuses }) => {
if (statuses && statuses.length === 0) { if (statuses?.length === 0) {
this.bottomedOut = true this.bottomedOut = true
} }
}) })

View file

@ -1,6 +1,6 @@
<template> <template>
<FAIcon <FAIcon
v-if="user && user.screen_name_ui_contains_non_ascii" v-if="user?.screen_name_ui_contains_non_ascii"
icon="code" icon="code"
:title="$t('unicode_domain_indicator.tooltip')" :title="$t('unicode_domain_indicator.tooltip')"
/> />

View file

@ -68,7 +68,7 @@
> >
<button <button
v-if="editable" v-if="editable"
:disabled="newName && newName.length === 0" :disabled="newName?.length === 0"
class="btn button-unstyled edit-banner-button" class="btn button-unstyled edit-banner-button"
@click="changeBanner" @click="changeBanner"
> >

View file

@ -34,15 +34,15 @@ const VideoAttachment = {
// If hasAudio is false, we've already marked this video to not have audio, // If hasAudio is false, we've already marked this video to not have audio,
// a video can't gain audio out of nowhere so don't bother checking again. // a video can't gain audio out of nowhere so don't bother checking again.
if (!this.hasAudio) return if (!this.hasAudio) return
if (typeof target.webkitAudioDecodedByteCount !== 'undefined') { if (target.webkitAudioDecodedByteCount !== undefined) {
// non-zero if video has audio track // non-zero if video has audio track
if (target.webkitAudioDecodedByteCount > 0) return if (target.webkitAudioDecodedByteCount > 0) return
} }
if (typeof target.mozHasAudio !== 'undefined') { if (target.mozHasAudio !== undefined) {
// true if video has audio track // true if video has audio track
if (target.mozHasAudio) return if (target.mozHasAudio) return
} }
if (typeof target.audioTracks !== 'undefined') { if (target.audioTracks !== undefined) {
if (target.audioTracks.length > 0) return if (target.audioTracks.length > 0) return
} }
this.hasAudio = false this.hasAudio = false

View file

@ -3,14 +3,12 @@ import {
find, find,
findIndex, findIndex,
first, first,
isArray,
last, last,
maxBy, maxBy,
merge, merge,
minBy, minBy,
omitBy, omitBy,
remove, remove,
slice,
} from 'lodash' } from 'lodash'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js' import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
@ -206,7 +204,7 @@ const addNewStatuses = (
}, },
) => { ) => {
// Sanity check // Sanity check
if (!isArray(statuses)) { if (!Array.isArray(statuses)) {
return false return false
} }
@ -410,7 +408,7 @@ export const mutations = {
const oldTimeline = state.timelines[timeline] const oldTimeline = state.timelines[timeline]
oldTimeline.newStatusCount = 0 oldTimeline.newStatusCount = 0
oldTimeline.visibleStatuses = slice(oldTimeline.statuses, 0, 50) oldTimeline.visibleStatuses = oldTimeline.statuses.slice(0, 50)
oldTimeline.minVisibleId = last(oldTimeline.visibleStatuses).id oldTimeline.minVisibleId = last(oldTimeline.visibleStatuses).id
oldTimeline.minId = oldTimeline.minVisibleId oldTimeline.minId = oldTimeline.minVisibleId
oldTimeline.visibleStatusesObject = {} oldTimeline.visibleStatusesObject = {}

View file

@ -1,14 +1,5 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import { import { compact, each, last, map, mergeWith } from 'lodash'
compact,
concat,
each,
isArray,
last,
map,
mergeWith,
uniq,
} from 'lodash'
import { import {
registerPushNotifications, registerPushNotifications,
@ -76,7 +67,7 @@ export const mergeOrAdd = (arr, obj, item) => {
} }
const mergeArrayLength = (oldValue, newValue) => { const mergeArrayLength = (oldValue, newValue) => {
if (isArray(oldValue) && isArray(newValue)) { if (Array.isArray(oldValue) && Array.isArray(newValue)) {
oldValue.length = newValue.length oldValue.length = newValue.length
return mergeWith(oldValue, newValue, mergeArrayLength) return mergeWith(oldValue, newValue, mergeArrayLength)
} }
@ -234,11 +225,11 @@ export const mutations = {
}, },
saveFriendIds(state, { id, friendIds }) { saveFriendIds(state, { id, friendIds }) {
const user = state.usersObject[id] const user = state.usersObject[id]
user.friendIds = uniq(concat(user.friendIds || [], friendIds)) user.friendIds = [...new Set([...(user.friendIds || []), ...friendIds])]
}, },
saveFollowerIds(state, { id, followerIds }) { saveFollowerIds(state, { id, followerIds }) {
const user = state.usersObject[id] const user = state.usersObject[id]
user.followerIds = uniq(concat(user.followerIds || [], followerIds)) user.followerIds = [...new Set([user.followerIds || [], ...followerIds])]
}, },
// Because frontend doesn't have a reason to keep these stuff in memory // Because frontend doesn't have a reason to keep these stuff in memory
// outside of viewing someones user profile. // outside of viewing someones user profile.

View file

@ -173,9 +173,9 @@ export const hex2rgb = (hex) => {
return result return result
? { ? {
r: parseInt(result[1], 16), r: Number.parseInt(result[1], 16),
g: parseInt(result[2], 16), g: Number.parseInt(result[2], 16),
b: parseInt(result[3], 16), b: Number.parseInt(result[3], 16),
} }
: null : null
} }
@ -271,7 +271,7 @@ export const getTextColor = function (bg, text, preserve) {
contrast = getContrastRatio(bg, convert(result).rgb) contrast = getContrastRatio(bg, convert(result).rgb)
} }
const base = typeof text.a !== 'undefined' ? { a: text.a } : {} const base = text.a !== undefined ? { a: text.a } : {}
return Object.assign(convert(result).rgb, base) return Object.assign(convert(result).rgb, base)
} }

View file

@ -177,7 +177,7 @@ export const parseUser = (data) => {
// deactivated was changed to is_active in Pleroma 2.3.0 // deactivated was changed to is_active in Pleroma 2.3.0
// so check if is_active is present // so check if is_active is present
output.deactivated = output.deactivated =
typeof data.pleroma.is_active !== 'undefined' data.pleroma.is_active !== undefined
? !data.pleroma.is_active // new backend ? !data.pleroma.is_active // new backend
: data.pleroma.deactivated // old backend : data.pleroma.deactivated // old backend
@ -372,7 +372,7 @@ export const parseNotification = (data) => {
} }
output.created_at = new Date(data.created_at) output.created_at = new Date(data.created_at)
output.id = parseInt(data.id) output.id = Number.parseInt(data.id)
return output return output
} }
@ -385,8 +385,8 @@ export const parseLinkHeaderPagination = (linkHeader, opts = {}) => {
const minId = parsedLinkHeader.prev?.min_id const minId = parsedLinkHeader.prev?.min_id
return { return {
maxId: flakeId ? maxId : parseInt(maxId, 10), maxId: flakeId ? maxId : Number.parseInt(maxId, 10),
minId: flakeId ? minId : parseInt(minId, 10), minId: flakeId ? minId : Number.parseInt(minId, 10),
} }
} }

View file

@ -14,7 +14,7 @@ export function StatusCodeError(statusCode, body, options, response) {
this.name = 'StatusCodeError' this.name = 'StatusCodeError'
this.statusCode = statusCode this.statusCode = statusCode
this.statusText = body.error || body.errors || body this.statusText = body.error || body.errors || body
this.details = JSON && JSON.stringify ? JSON.stringify(body) : body this.details = JSON.stringify(body)
this.errorData = body.error || body.errors this.errorData = body.error || body.errors
this.message = this.statusCode + ' - ' + this.statusText this.message = this.statusCode + ' - ' + this.statusText
this.error = body // legacy attribute this.error = body // legacy attribute

View file

@ -1,5 +1,3 @@
import { uniq } from 'lodash'
import * as DateUtils from 'src/services/date_utils/date_utils.js' import * as DateUtils from 'src/services/date_utils/date_utils.js'
const pollFallbackValues = { const pollFallbackValues = {
@ -19,9 +17,9 @@ export const pollFormToMasto = (poll) => {
pollFallback(poll, 'expiryAmount'), pollFallback(poll, 'expiryAmount'),
) )
const options = uniq( const options = [
pollFallback(poll, 'options').filter((option) => option !== ''), ...new Set(pollFallback(poll, 'options').filter((option) => option !== '')),
) ]
if (options.length < 2) { if (options.length < 2) {
return { errorKey: 'polls.not_enough_options' } return { errorKey: 'polls.not_enough_options' }
} }

View file

@ -125,10 +125,7 @@ const generateTheme = (inputRuleset, callbacks, debug) => {
const processChunk = () => { const processChunk = () => {
const chunk = chunks[counter] const chunk = chunks[counter]
Promise.all(chunk.map((x) => x())).then((result) => { Promise.all(chunk.map((x) => x())).then((result) => {
getCssRules( getCssRules(result.filter(Boolean), debug).forEach((rule) => {
result.filter((x) => x),
debug,
).forEach((rule) => {
onNewRule(rule, true) onNewRule(rule, true)
}) })
// const t1 = performance.now() // const t1 = performance.now()
@ -253,7 +250,9 @@ const extractStyleConfig = ({
contentColumnWidth, contentColumnWidth,
notifsColumnWidth, notifsColumnWidth,
themeEditorMinWidth: themeEditorMinWidth:
parseInt(themeEditorMinWidth) === 0 ? 'fit-content' : themeEditorMinWidth, Number.parseInt(themeEditorMinWidth) === 0
? 'fit-content'
: themeEditorMinWidth,
emojiReactionsScale, emojiReactionsScale,
emojiSize, emojiSize,
navbarSize, navbarSize,

View file

@ -4,7 +4,7 @@ function urlBase64ToUint8Array(base64String) {
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/') const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/')
const rawData = window.atob(base64) const rawData = window.atob(base64)
return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0))) return Uint8Array.from([...rawData].map((char) => char.codePointAt(0)))
} }
export function isSWSupported() { export function isSWSupported() {

View file

@ -104,7 +104,7 @@ export const getCssRules = (rules, debug) =>
: '', : '',
' --background: ' + v, ' --background: ' + v,
] ]
.filter((x) => x) .filter(Boolean)
.join(';\n') .join(';\n')
} }
const color = getCssColorString( const color = getCssColorString(
@ -115,7 +115,7 @@ export const getCssRules = (rules, debug) =>
if (rule.directives.backgroundNoCssColor !== 'yes') { if (rule.directives.backgroundNoCssColor !== 'yes') {
cssDirectives.push('background-color: ' + color) cssDirectives.push('background-color: ' + color)
} }
return cssDirectives.filter((x) => x).join(';\n') return cssDirectives.filter(Boolean).join(';\n')
} }
case 'blur': { case 'blur': {
const cssDirectives = [] const cssDirectives = []
@ -157,7 +157,7 @@ export const getCssRules = (rules, debug) =>
return null return null
} }
}) })
.filter((x) => x) .filter(Boolean)
.map((x) => ' ' + x + ';') .map((x) => ' ' + x + ';')
.join('\n') .join('\n')
@ -172,10 +172,10 @@ export const getCssRules = (rules, debug) =>
virtualDirectives, virtualDirectives,
footer, footer,
] ]
.filter((x) => x) .filter(Boolean)
.join('\n') .join('\n')
}) })
.filter((x) => x) .filter(Boolean)
export const getScopedVersion = (rules, newScope) => { export const getScopedVersion = (rules, newScope) => {
return rules.map((x) => { return rules.map((x) => {

View file

@ -62,6 +62,6 @@ export const serialize = (ruleset) => {
return `${header} {\n${content.join(';\n')}\n}` return `${header} {\n${content.join(';\n')}\n}`
}) })
.filter((x) => x) .filter(Boolean)
.join('\n\n') .join('\n\n')
} }

View file

@ -558,9 +558,9 @@ export const convertTheme2To3 = (data) => {
) )
const flatExtRules = extendedRules const flatExtRules = extendedRules
.filter((x) => x) .filter(Boolean)
.reduce((acc, x) => [...acc, ...x], []) .reduce((acc, x) => [...acc, ...x], [])
.filter((x) => x) .filter(Boolean)
.reduce((acc, x) => [...acc, ...x], []) .reduce((acc, x) => [...acc, ...x], [])
return [ return [

View file

@ -229,10 +229,7 @@ export const getLayerSlot = (
*/ */
export const SLOT_ORDERED = topoSort( export const SLOT_ORDERED = topoSort(
Object.entries(SLOT_INHERITANCE) Object.entries(SLOT_INHERITANCE)
.sort( .sort(([, aV], [, bV]) => (aV?.priority || 0) - (bV?.priority || 0))
([, aV], [, bV]) =>
((aV && aV.priority) || 0) - ((bV && bV.priority) || 0),
)
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}), .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}),
) )
@ -408,7 +405,7 @@ export const getColors = (sourceColors, sourceOpacity) =>
delete outputColor.a delete outputColor.a
} else { } else {
// Otherwise try to assign opacity // Otherwise try to assign opacity
if (dependencyColor && dependencyColor.a === 0) { if (dependencyColor?.a === 0) {
// transparent dependency shall make dependents transparent too // transparent dependency shall make dependents transparent too
outputColor.a = 0 outputColor.a = 0
} else { } else {
@ -523,7 +520,7 @@ export const generateColors = (themeData) => {
(acc, [k, v]) => { (acc, [k, v]) => {
if (!v) return acc if (!v) return acc
acc.solid[k] = rgb2hex(v) acc.solid[k] = rgb2hex(v)
acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgba2css(v) acc.complete[k] = v.a === undefined ? rgb2hex(v) : rgba2css(v)
return acc return acc
}, },
{ complete: {}, solid: {} }, { complete: {}, solid: {} },
@ -545,7 +542,7 @@ export const generateColors = (themeData) => {
export const generateRadii = (input) => { export const generateRadii = (input) => {
let inputRadii = input.radii || {} let inputRadii = input.radii || {}
// v1 -> v2 // v1 -> v2
if (typeof input.btnRadius !== 'undefined') { if (input.btnRadius !== undefined) {
inputRadii = Object.entries(input) inputRadii = Object.entries(input)
.filter(([k]) => k.endsWith('Radius')) .filter(([k]) => k.endsWith('Radius'))
.reduce((acc, e) => { .reduce((acc, e) => {

View file

@ -338,10 +338,10 @@ export const init = ({
const relevantRules = ruleset.filter((r) => r.component === component.name) const relevantRules = ruleset.filter((r) => r.component === component.name)
const backgrounds = relevantRules const backgrounds = relevantRules
.map((r) => r.directives.background) .map((r) => r.directives.background)
.filter((x) => x) .filter(Boolean)
const opacities = relevantRules const opacities = relevantRules
.map((r) => r.directives.opacity) .map((r) => r.directives.opacity)
.filter((x) => x) .filter(Boolean)
if ( if (
backgrounds.some((x) => x.match(/--parent/)) || backgrounds.some((x) => x.match(/--parent/)) ||
opacities.some((x) => x != null && x < 1) opacities.some((x) => x != null && x < 1)
@ -596,7 +596,7 @@ export const init = ({
const shadow = value const shadow = value
.split(/,/g) .split(/,/g)
.map((s) => s.trim()) .map((s) => s.trim())
.filter((x) => x) .filter(Boolean)
dynamicVars[k] = shadow dynamicVars[k] = shadow
if (combination.component === rootComponentName) { if (combination.component === rootComponentName) {
staticVars[k.substring(2)] = shadow staticVars[k.substring(2)] = shadow
@ -752,7 +752,7 @@ export const init = ({
return processCombination(combination) return processCombination(combination)
} }
}) })
.filter((x) => x) .filter(Boolean)
const t2 = performance.now() const t2 = performance.now()
if (debug) { if (debug) {
console.debug('Eager processing took ' + (t2 - t1) + ' ms') console.debug('Eager processing took ' + (t2 - t1) + ' ms')

View file

@ -11,6 +11,6 @@ const generateProfileLink = (id, screenName, restrictedNicknames) => {
} }
} }
const isExternal = (screenName) => screenName && screenName.includes('@') const isExternal = (screenName) => screenName?.includes('@')
export default generateProfileLink export default generateProfileLink

View file

@ -1,4 +1,4 @@
import { cloneDeep, differenceWith, flatten, get, isEqual, set } from 'lodash' import { cloneDeep, differenceWith, get, isEqual, set } from 'lodash'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { useOAuthStore } from 'src/stores/oauth.js' import { useOAuthStore } from 'src/stores/oauth.js'
@ -209,11 +209,11 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
} }
// Getting all group-keys used in config // Getting all group-keys used in config
const allGroupKeys = flatten( const allGroupKeys = Object.entries(this.config)
Object.entries(this.config).map(([group, lv1data]) => .map(([group, lv1data]) =>
Object.keys(lv1data).map((key) => ({ group, key })), Object.keys(lv1data).map((key) => ({ group, key })),
), )
) .flat()
// Only using group-keys where there are changes detected // Only using group-keys where there are changes detected
const changedGroupKeys = allGroupKeys.filter(({ group, key }) => { const changedGroupKeys = allGroupKeys.filter(({ group, key }) => {

View file

@ -74,7 +74,7 @@ export const useAnnouncementsStore = defineStore('announcements', {
} catch (error) { } catch (error) {
// If and only if backend does not support announcements, it would return 404. // If and only if backend does not support announcements, it would return 404.
// In this case, silently ignores it. // In this case, silently ignores it.
if (error && error.statusCode === 404) { if (error?.statusCode === 404) {
this.supportsAnnouncements = false this.supportsAnnouncements = false
} else { } else {
throw error throw error

View file

@ -747,7 +747,7 @@ export const useInterfaceStore = defineStore('interface', {
this.styleDataUsed, this.styleDataUsed,
paletteIss, paletteIss,
hacks, hacks,
].filter((x) => x) ].filter(Boolean)
return applyTheme( return applyTheme(
rulesetArray.flat(), rulesetArray.flat(),
@ -790,7 +790,7 @@ export const normalizeThemeData = (input) => {
// New theme presets don't have 'theme' property, they use 'source' // New theme presets don't have 'theme' property, they use 'source'
let out // shout, shout let it all out let out // shout, shout let it all out
if (themeSource && themeSource.themeEngineVersion === CURRENT_VERSION) { if (themeSource?.themeEngineVersion === CURRENT_VERSION) {
// There are some themes in wild that have completely broken source // There are some themes in wild that have completely broken source
out = { ...(themeData || {}), ...themeSource } out = { ...(themeData || {}), ...themeSource }
} else { } else {

View file

@ -4,13 +4,12 @@ import {
clamp, clamp,
cloneDeep, cloneDeep,
findLastIndex, findLastIndex,
flatten,
get, get,
groupBy, groupBy,
isEqual, isEqual,
last,
set, set,
take, take,
takeRight,
uniqWith, uniqWith,
unset, unset,
} from 'lodash' } from 'lodash'
@ -222,15 +221,16 @@ export const _mergeFlags = (recent, stale, allFlagKeys) => {
export const _mergeJournal = (...journals) => { export const _mergeJournal = (...journals) => {
// Ignore invalid journal entries // Ignore invalid journal entries
const allJournals = flatten( const allJournals = journals
journals.map((j) => (Array.isArray(j) ? j : [])), .map((j) => (Array.isArray(j) ? j : []))
).filter( .flat()
(entry) => .filter(
Object.hasOwn(entry, 'path') && (entry) =>
Object.hasOwn(entry, 'operation') && Object.hasOwn(entry, 'path') &&
Object.hasOwn(entry, 'args') && Object.hasOwn(entry, 'operation') &&
Object.hasOwn(entry, 'timestamp'), Object.hasOwn(entry, 'args') &&
) Object.hasOwn(entry, 'timestamp'),
)
const grouped = groupBy(allJournals, 'path') const grouped = groupBy(allJournals, 'path')
const trimmedGrouped = Object.entries(grouped).map(([path, rawJournal]) => { const trimmedGrouped = Object.entries(grouped).map(([path, rawJournal]) => {
const journal = rawJournal const journal = rawJournal
@ -271,13 +271,14 @@ export const _mergeJournal = (...journals) => {
}) })
} else if (path.startsWith('simple')) { } else if (path.startsWith('simple')) {
// Only the last record is important // Only the last record is important
return takeRight(journal) return [last(journal)]
} else { } else {
return journal return journal
} }
}) })
const flat = flatten(trimmedGrouped) const flat = trimmedGrouped
.flat()
.map((data, index) => ({ data, index })) .map((data, index) => ({ data, index }))
.toSorted(({ data: a, index: ai }, { data: b, index: bi }) => { .toSorted(({ data: a, index: ai }, { data: b, index: bi }) => {
if (a.timestamp === b.timestamp) { if (a.timestamp === b.timestamp) {

View file

@ -2,10 +2,9 @@ import {
merge as _merge, merge as _merge,
clone, clone,
cloneDeep, cloneDeep,
flatten,
groupBy, groupBy,
isEqual, isEqual,
takeRight, last,
} from 'lodash' } from 'lodash'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { toRaw } from 'vue' import { toRaw } from 'vue'
@ -117,25 +116,26 @@ export const _getRecentData = (cache, live, isTest) => {
const _mergeJournal = (...journals) => { const _mergeJournal = (...journals) => {
// Ignore invalid journal entries // Ignore invalid journal entries
const allJournals = flatten( const allJournals = journals
journals.map((j) => (Array.isArray(j) ? j : [])), .map((j) => (Array.isArray(j) ? j : []))
).filter( .flat()
(entry) => .filter(
Object.hasOwn(entry, 'user') && (entry) =>
Object.hasOwn(entry, 'operation') && Object.hasOwn(entry, 'user') &&
Object.hasOwn(entry, 'args') && Object.hasOwn(entry, 'operation') &&
Object.hasOwn(entry, 'timestamp'), Object.hasOwn(entry, 'args') &&
) Object.hasOwn(entry, 'timestamp'),
)
const grouped = groupBy(allJournals, 'user') const grouped = groupBy(allJournals, 'user')
const trimmedGrouped = Object.entries(grouped).map(([user, journal]) => { const trimmedGrouped = Object.entries(grouped).map(([user, journal]) => {
// side effect // side effect
journal.sort((a, b) => (a.timestamp > b.timestamp ? 1 : -1)) journal.sort((a, b) => (a.timestamp > b.timestamp ? 1 : -1))
return takeRight(journal) return [last(journal)]
}) })
return flatten(trimmedGrouped).sort((a, b) => return trimmedGrouped
a.timestamp > b.timestamp ? 1 : -1, .flat()
) .sort((a, b) => (a.timestamp > b.timestamp ? 1 : -1))
} }
export const _mergeHighlights = (recent, stale) => { export const _mergeHighlights = (recent, stale) => {

View file

@ -132,7 +132,7 @@ export const waitForEvent = (
return vi.waitFor( return vi.waitFor(
() => { () => {
const e = wrapper.emitted(event) const e = wrapper.emitted(event)
if (e && e.length >= timesEmitted) { if (e?.length >= timesEmitted) {
return return
} }
throw new Error('event is not emitted') throw new Error('event is not emitted')

View file

@ -7,100 +7,92 @@ import {
} from 'src/services/entity_normalizer/entity_normalizer.service.js' } from 'src/services/entity_normalizer/entity_normalizer.service.js'
const makeMockUserMasto = (overrides = {}) => { const makeMockUserMasto = (overrides = {}) => {
return Object.assign( return {
{ acct: 'hj',
acct: 'hj', avatar:
avatar: 'https://shigusegubu.club/media/1657b945-8d5b-4ce6-aafb-4c3fc5772120/8ce851029af84d55de9164e30cc7f46d60cbf12eee7e96c5c0d35d9038ddade1.png',
'https://shigusegubu.club/media/1657b945-8d5b-4ce6-aafb-4c3fc5772120/8ce851029af84d55de9164e30cc7f46d60cbf12eee7e96c5c0d35d9038ddade1.png', avatar_static:
avatar_static: 'https://shigusegubu.club/media/1657b945-8d5b-4ce6-aafb-4c3fc5772120/8ce851029af84d55de9164e30cc7f46d60cbf12eee7e96c5c0d35d9038ddade1.png',
'https://shigusegubu.club/media/1657b945-8d5b-4ce6-aafb-4c3fc5772120/8ce851029af84d55de9164e30cc7f46d60cbf12eee7e96c5c0d35d9038ddade1.png', bot: false,
bot: false, created_at: '2017-12-17T21:54:14.000Z',
created_at: '2017-12-17T21:54:14.000Z', display_name: 'whatever whatever whatever witch',
display_name: 'whatever whatever whatever witch', emojis: [],
emojis: [], fields: [],
fields: [], followers_count: 705,
followers_count: 705, following_count: 326,
following_count: 326, header:
header: 'https://shigusegubu.club/media/7ab024d9-2a8a-4fbc-9ce8-da06756ae2db/6aadefe4e264133bc377ab450e6b045b6f5458542a5c59e6c741f86107f0388b.png',
'https://shigusegubu.club/media/7ab024d9-2a8a-4fbc-9ce8-da06756ae2db/6aadefe4e264133bc377ab450e6b045b6f5458542a5c59e6c741f86107f0388b.png', header_static:
header_static: 'https://shigusegubu.club/media/7ab024d9-2a8a-4fbc-9ce8-da06756ae2db/6aadefe4e264133bc377ab450e6b045b6f5458542a5c59e6c741f86107f0388b.png',
'https://shigusegubu.club/media/7ab024d9-2a8a-4fbc-9ce8-da06756ae2db/6aadefe4e264133bc377ab450e6b045b6f5458542a5c59e6c741f86107f0388b.png', id: '1',
id: '1', locked: false,
locked: false, note: 'Volatile Internet Weirdo. Name pronounced as Hee Jay. JS and Java dark arts mage, Elixir trainee. I love sampo and lain. Matrix is <span><a data-user="1" href="https://shigusegubu.club/users/hj">@<span>hj</span></a></span>:matrix.heldscal.la Pronouns are whatever. Do not DM me unless it\'s truly private matter and you\'re instance\'s admin or you risk your DM to be reposted publicly.Wish i was Finnish girl.',
note: 'Volatile Internet Weirdo. Name pronounced as Hee Jay. JS and Java dark arts mage, Elixir trainee. I love sampo and lain. Matrix is <span><a data-user="1" href="https://shigusegubu.club/users/hj">@<span>hj</span></a></span>:matrix.heldscal.la Pronouns are whatever. Do not DM me unless it\'s truly private matter and you\'re instance\'s admin or you risk your DM to be reposted publicly.Wish i was Finnish girl.', pleroma: { confirmation_pending: false, tags: null },
pleroma: { confirmation_pending: false, tags: null }, source: { note: '', privacy: 'public', sensitive: false },
source: { note: '', privacy: 'public', sensitive: false }, statuses_count: 41775,
statuses_count: 41775, url: 'https://shigusegubu.club/users/hj',
url: 'https://shigusegubu.club/users/hj', username: 'hj',
username: 'hj', ...overrides,
}, }
overrides,
)
} }
const makeMockStatusMasto = (overrides = {}) => { const makeMockStatusMasto = (overrides = {}) => {
return Object.assign( return {
{ account: makeMockUserMasto(),
account: makeMockUserMasto(), application: { name: 'Web', website: null },
application: { name: 'Web', website: null }, content:
content: '<span><a data-user="14660" href="https://pleroma.soykaf.com/users/sampo">@<span>sampo</span></a></span> god i wish i was there',
'<span><a data-user="14660" href="https://pleroma.soykaf.com/users/sampo">@<span>sampo</span></a></span> god i wish i was there', created_at: '2019-01-17T16:29:23.000Z',
created_at: '2019-01-17T16:29:23.000Z', emojis: [],
emojis: [], favourited: false,
favourited: false, favourites_count: 1,
favourites_count: 1, id: '10423476',
id: '10423476', in_reply_to_account_id: '14660',
in_reply_to_account_id: '14660', in_reply_to_id: '10423197',
in_reply_to_id: '10423197', language: null,
language: null, media_attachments: [],
media_attachments: [], mentions: [
mentions: [ {
{ acct: 'sampo@pleroma.soykaf.com',
acct: 'sampo@pleroma.soykaf.com', id: '14660',
id: '14660', url: 'https://pleroma.soykaf.com/users/sampo',
url: 'https://pleroma.soykaf.com/users/sampo', username: 'sampo',
username: 'sampo',
},
],
muted: false,
reblog: null,
reblogged: false,
reblogs_count: 0,
replies_count: 0,
sensitive: false,
spoiler_text: '',
tags: [],
uri: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
url: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
visibility: 'public',
pleroma: {
local: true,
}, },
],
muted: false,
reblog: null,
reblogged: false,
reblogs_count: 0,
replies_count: 0,
sensitive: false,
spoiler_text: '',
tags: [],
uri: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
url: 'https://shigusegubu.club/objects/16033fbb-97c0-4f0e-b834-7abb92fb8639',
visibility: 'public',
pleroma: {
local: true,
}, },
overrides, ...overrides,
) }
} }
const makeMockEmojiMasto = (overrides = [{}]) => { const makeMockEmojiMasto = (overrides = [{}]) => {
return [ return [
Object.assign( {
{ shortcode: 'image',
shortcode: 'image', static_url: 'https://example.com/image.png',
static_url: 'https://example.com/image.png', url: 'https://example.com/image.png',
url: 'https://example.com/image.png', visible_in_picker: false,
visible_in_picker: false, ...overrides[0],
}, },
overrides[0], {
), shortcode: 'thinking',
Object.assign( static_url: 'https://example.com/think.png',
{ url: 'https://example.com/think.png',
shortcode: 'thinking', visible_in_picker: false,
static_url: 'https://example.com/think.png', ...overrides[1],
url: 'https://example.com/think.png', },
visible_in_picker: false,
},
overrides[1],
),
] ]
} }