Remove unused code

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2024-08-18 19:42:45 +02:00
parent 610b21d40a
commit cbee2ff018
15 changed files with 10 additions and 251 deletions

View File

@ -21,9 +21,6 @@ const getLinks = (response: Pick<Response, 'headers'>): LinkHeader =>
const getNextLink = (response: Pick<Response, 'headers'>): string | undefined =>
getLinks(response).refs.find(link => link.rel === 'next')?.uri;
const getPrevLink = (response: Pick<Response, 'headers'>): string | undefined =>
getLinks(response).refs.find(link => link.rel === 'prev')?.uri;
/**
* Dumb client for grabbing static files.
* It uses FE_SUBDIRECTORY and parses JSON if possible.
@ -58,7 +55,6 @@ export {
type PlfeResponse,
getLinks,
getNextLink,
getPrevLink,
staticFetch,
getClient,
};

View File

@ -4,6 +4,7 @@ import {
groupRelationshipSchema,
groupSchema,
instanceSchema,
previewCardSchema,
relationshipSchema,
statusSchema,
GroupRoles,
@ -12,16 +13,12 @@ import {
type GroupMember,
type GroupRelationship,
type Instance,
type PreviewCard,
type Relationship,
type Status,
} from 'pl-api';
import { v4 as uuidv4 } from 'uuid';
import {
cardSchema,
type Card,
} from 'soapbox/schemas';
import type { PartialDeep } from 'type-fest';
// TODO: there's probably a better way to create these factory functions.
@ -33,8 +30,8 @@ const buildAccount = (props: PartialDeep<Account> = {}): Account =>
url: `https://soapbox.test/users/${uuidv4()}`,
}, props));
const buildCard = (props: PartialDeep<Card> = {}): Card =>
cardSchema.parse(Object.assign({
const buildCard = (props: PartialDeep<PreviewCard> = {}): PreviewCard =>
previewCardSchema.parse(Object.assign({
url: 'https://soapbox.test',
}, props));

View File

@ -1,11 +0,0 @@
import { cardSchema } from './card';
describe('cardSchema', () => {
it('adds base fields', () => {
const card = { url: 'https://soapbox.test' };
const result = cardSchema.parse(card);
expect(result.type).toEqual('link');
expect(result.url).toEqual(card.url);
});
});

View File

@ -1,92 +0,0 @@
import punycode from 'punycode';
import DOMPurify from 'isomorphic-dompurify';
import { z } from 'zod';
const IDNA_PREFIX = 'xn--';
/**
* Card (aka link preview).
* https://docs.joinmastodon.org/entities/card/
*/
const cardSchema = z.object({
author_name: z.string().catch(''),
author_url: z.string().url().catch(''),
blurhash: z.string().nullable().catch(null),
description: z.string().catch(''),
embed_url: z.string().url().catch(''),
height: z.number().catch(0),
html: z.string().catch(''),
image: z.string().nullable().catch(null),
pleroma: z.object({
opengraph: z.object({
width: z.number(),
height: z.number(),
html: z.string(),
thumbnail_url: z.string().url(),
}).optional().catch(undefined),
}).optional().catch(undefined),
provider_name: z.string().catch(''),
provider_url: z.string().url().catch(''),
title: z.string().catch(''),
type: z.enum(['link', 'photo', 'video', 'rich']).catch('link'),
url: z.string().url(),
width: z.number().catch(0),
}).transform(({ pleroma, ...card }) => {
if (!card.provider_name) {
card.provider_name = decodeIDNA(new URL(card.url).hostname);
}
if (pleroma?.opengraph) {
if (!card.width && !card.height) {
card.width = pleroma.opengraph.width;
card.height = pleroma.opengraph.height;
}
if (!card.html) {
card.html = pleroma.opengraph.html;
}
if (!card.image) {
card.image = pleroma.opengraph.thumbnail_url;
}
}
const html = DOMPurify.sanitize(card.html, {
ALLOWED_TAGS: ['iframe'],
ALLOWED_ATTR: ['src', 'width', 'height', 'frameborder', 'allowfullscreen'],
RETURN_DOM: true,
});
html.querySelectorAll('iframe').forEach((frame) => {
try {
const src = new URL(frame.src);
if (src.protocol !== 'https:') {
throw new Error('iframe must be https');
}
if (src.origin === location.origin) {
throw new Error('iframe must not be same origin');
}
frame.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-presentation');
} catch (e) {
frame.remove();
}
});
card.html = html.innerHTML;
if (!card.html) {
card.type = 'link';
}
return card;
});
const decodeIDNA = (domain: string): string => domain
.split('.')
.map(part => part.indexOf(IDNA_PREFIX) === 0 ? punycode.decode(part.slice(IDNA_PREFIX.length)) : part)
.join('.');
type Card = z.infer<typeof cardSchema>;
export { cardSchema, type Card };

View File

@ -1,6 +1,5 @@
export { adminAnnouncementSchema, type AdminAnnouncement } from './admin-announcement';
export { cardSchema, type Card } from './card';
export { domainSchema, type Domain } from './domain';
export { moderationLogEntrySchema, type ModerationLogEntry } from './moderation-log-entry';
export { relaySchema, type Relay } from './relay';
export { ruleSchema, adminRuleSchema, type Rule, type AdminRule } from './rule';
export { adminRuleSchema, type AdminRule } from './rule';

View File

@ -1,44 +0,0 @@
// import { pollSchema } from './poll';
describe('normalizePoll()', () => {
it('adds base fields', () => {
const poll = { id: '1', options: [{ title: 'Apples' }, { title: 'Oranges' }] };
const result = pollSchema.parse(poll);
const expected = {
options: [
{ title: 'Apples', votes_count: 0 },
{ title: 'Oranges', votes_count: 0 },
],
emojis: [],
expired: false,
multiple: false,
voters_count: 0,
votes_count: 0,
own_votes: null,
voted: false,
};
expect(result).toMatchObject(expected);
});
it('normalizes a Pleroma logged-out poll', async () => {
const { poll } = await import('soapbox/__fixtures__/pleroma-status-with-poll.json');
const result = pollSchema.parse(poll);
// Adds logged-in fields
expect(result.voted).toBe(false);
expect(result.own_votes).toBe(null);
});
it('normalizes poll with emojis', async () => {
const { poll } = await import('soapbox/__fixtures__/pleroma-status-with-poll-with-emojis.json');
const result = pollSchema.parse(poll);
// Emojifies poll options
expect(result.options[1]?.title_emojified)
.toContain('emojione');
expect(result.emojis[1]?.shortcode).toEqual('soapbox');
});
});

View File

@ -1,22 +1,12 @@
import { z } from 'zod';
const baseRuleSchema = z.object({
const adminRuleSchema = z.object({
id: z.string(),
text: z.string().catch(''),
hint: z.string().catch(''),
});
const ruleSchema = z.preprocess((data: any) => ({
...data,
hint: data.hint || data.subtext,
}), baseRuleSchema);
type Rule = z.infer<typeof ruleSchema>;
const adminRuleSchema = baseRuleSchema.extend({
priority: z.number().nullable().catch(null),
});
type AdminRule = z.infer<typeof adminRuleSchema>;
export { ruleSchema, adminRuleSchema, type Rule, type AdminRule };
export { adminRuleSchema, type AdminRule };

View File

@ -8,13 +8,4 @@ const normalizeUsername = (username: string): string => {
}
};
const slugify = (text: string): string => text
.trim()
.toLowerCase()
.replace(/[^\w]/g, '-') // replace non-word characters with a hyphen
.replace(/-+/g, '-'); // replace multiple hyphens with a single hyphen
export {
normalizeUsername,
slugify,
};
export { normalizeUsername };

View File

@ -1,9 +0,0 @@
interface LegacyMap {
get(key: any): unknown;
getIn(keyPath: any[]): unknown;
toJS(): any;
}
export {
type LegacyMap,
};

View File

@ -1,8 +1,5 @@
import z from 'zod';
/** Use new value only if old value is undefined */
const mergeDefined = (oldVal: any, newVal: any) => oldVal === undefined ? newVal : oldVal;
const makeEmojiMap = (emojis: any) => emojis.reduce((obj: any, emoji: any) => {
obj[`:${emoji.shortcode}:`] = emoji;
return obj;
@ -11,33 +8,7 @@ const makeEmojiMap = (emojis: any) => emojis.reduce((obj: any, emoji: any) => {
/** Normalize entity ID */
const normalizeId = (id: any): string | null => z.string().nullable().catch(null).parse(id);
type Normalizer<V, R> = (value: V) => R;
/**
* Allows using any legacy normalizer function as a zod schema.
*
* @example
* ```ts
* const statusSchema = toSchema(normalizeStatus);
* statusSchema.parse(status);
* ```
*/
const toSchema = <V, R>(normalizer: Normalizer<V, R>) => z.custom<V>().transform<R>(normalizer);
/** Legacy normalizer transition helper function. */
const maybeFromJS = (value: any): unknown => {
if ('toJS' in value) {
return value.toJS();
} else {
return value;
}
};
export {
type Normalizer,
mergeDefined,
makeEmojiMap,
normalizeId,
toSchema,
maybeFromJS,
};

View File

@ -2,7 +2,7 @@ import React from 'react';
import { render, screen } from 'soapbox/jest/test-helpers';
import { isIntegerId, secondsToDays, shortNumberFormat } from './numbers';
import { isIntegerId, shortNumberFormat } from './numbers';
test('isIntegerId()', () => {
expect(isIntegerId('0')).toBe(true);
@ -14,14 +14,6 @@ test('isIntegerId()', () => {
expect(isIntegerId(null as any)).toBe(false);
expect(isIntegerId(undefined as any)).toBe(false);
});
test('secondsToDays', () => {
expect(secondsToDays(604800)).toEqual(7);
expect(secondsToDays(1209600)).toEqual(14);
expect(secondsToDays(2592000)).toEqual(30);
expect(secondsToDays(7776000)).toEqual(90);
});
describe('shortNumberFormat', () => {
test('handles non-numbers', () => {
render(<div data-testid='num'>{shortNumberFormat('not-number')}</div>, undefined, null);

View File

@ -8,8 +8,6 @@ const isNumber = (value: unknown): value is number => typeof value === 'number'
/** The input is a number and is not NaN. */
const realNumberSchema = z.coerce.number().refine(n => !isNaN(n));
const secondsToDays = (seconds: number) => Math.floor(seconds / (3600 * 24));
const roundDown = (num: number) => {
if (num >= 100 && num < 1000) {
num = Math.floor(num);
@ -58,7 +56,6 @@ const isIntegerId = (id: string): boolean => new RegExp(/^-?[0-9]+$/g).test(id);
export {
isNumber,
realNumberSchema,
secondsToDays,
roundDown,
shortNumberFormat,
isIntegerId,

View File

@ -1,15 +1,7 @@
import { useEffect } from 'react';
import type { Location } from 'soapbox/types/history';
const LOCAL_STORAGE_REDIRECT_KEY = 'plfe:redirect-uri';
const cacheCurrentUrl = (location: Location) => {
const actualUrl = encodeURIComponent(`${location.pathname}${location.search}`);
localStorage.setItem(LOCAL_STORAGE_REDIRECT_KEY, actualUrl);
return actualUrl;
};
const getRedirectUrl = () => {
let redirectUri = localStorage.getItem(LOCAL_STORAGE_REDIRECT_KEY);
if (redirectUri) {
@ -34,4 +26,4 @@ const useCachedLocationHandler = () => {
return null;
};
export { cacheCurrentUrl, getRedirectUrl, useCachedLocationHandler };
export { getRedirectUrl, useCachedLocationHandler };

View File

@ -56,15 +56,6 @@ const textForScreenReader = (
return values.join(', ');
};
/** Get reblogged status if any, otherwise return the original status. */
const getActualStatus = <T extends { reblog: T | null }>(status: T): Omit<T, 'reblog'> => {
if (status?.reblog && typeof status?.reblog === 'object') {
return status.reblog;
} else {
return status;
}
};
const getStatusIdsFromLinksInContent = (content: string): string[] => {
const urls = content.match(RegExp(`${window.location.origin}/@([a-z\\d_-]+(?:@[^@\\s]+)?)/posts/[a-z0-9]+(?!\\S)`, 'gi'));
@ -81,6 +72,5 @@ export {
shouldHaveCard,
hasIntegerMediaIds,
textForScreenReader,
getActualStatus,
getStatusIdsFromLinksInContent,
};