Merge remote-tracking branch 'origin/develop' into ts-redux

remove-makegetotheraccounts
Alex Gleason 2022-03-18 15:33:56 -05:00
commit c8c5a6b077
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
56 zmienionych plików z 1190 dodań i 644 usunięć

Wyświetl plik

@ -254,18 +254,12 @@ module.exports = {
}, },
overrides: [ overrides: [
{ {
files: ['**/*.tsx'], files: ['**/*.ts', '**/*.tsx'],
rules: { rules: {
'no-undef': 'off', // https://stackoverflow.com/a/69155899
'react/prop-types': 'off', 'react/prop-types': 'off',
}, },
}, parser: '@typescript-eslint/parser',
// Disable no-undef in TypeScript
// https://stackoverflow.com/a/69155899
{
files: ['*.ts', '*.tsx'],
rules: {
'no-undef': 'off',
},
}, },
], ],
}; };

8
.gitignore vendored
Wyświetl plik

@ -24,7 +24,7 @@ yarn-error.log*
!/custom/**/.gitkeep !/custom/**/.gitkeep
# surge.sh # surge.sh
CNAME /CNAME
AUTH /AUTH
CORS /CORS
ROUTER /ROUTER

Wyświetl plik

@ -2,10 +2,14 @@
![Soapbox FE Screenshot](soapbox-screenshot.png) ![Soapbox FE Screenshot](soapbox-screenshot.png)
**Soapbox FE** is a frontend for Pleroma with a focus on custom branding and ease of use. **Soapbox FE** is a frontend for Mastodon and Pleroma with a focus on custom branding and ease of use.
It's part of the [Soapbox](https://soapbox.pub) project. It's part of the [Soapbox](https://soapbox.pub) project.
# :rocket: Deploy on Pleroma ## Try it out
Visit https://fe.soapbox.pub/ and point it to your favorite instance.
## :rocket: Deploy on Pleroma
Installing Soapbox FE on an existing Pleroma server is extremely easy. Installing Soapbox FE on an existing Pleroma server is extremely easy.
Just ssh into the server and download a .zip of the latest build: Just ssh into the server and download a .zip of the latest build:

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 14 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.0 KiB

Wyświetl plik

@ -1,116 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg <svg
inkscape:export-ydpi="240" height="100px"
inkscape:export-xdpi="240" width="100px"
inkscape:export-filename="/home/alex/Projects/docker-tribe/avi.png" fill="#000000"
sodipodi:docname="avatar.svg"
width="120"
height="120"
viewBox="0 0 31.75 31.750001"
version="1.1" version="1.1"
id="svg8" x="0px"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" y="0px"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" viewBox="0 0 95 95"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" enable-background="new 0 0 95 95"
xml:space="preserve"
id="svg4"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#" xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"> xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
<defs id="metadata10"><rdf:RDF><cc:Work
id="defs2" /> rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
<sodipodi:namedview rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
inkscape:window-maximized="1" id="defs8" /><rect
inkscape:window-y="30" style="opacity:1;vector-effect:none;fill:#f2f2f2;fill-opacity:1;stroke:none;stroke-width:3.79999995;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
inkscape:window-x="0" id="rect819"
inkscape:window-height="1019" width="95"
inkscape:window-width="1920" height="95"
id="base" x="0"
pagecolor="#ffffff" y="0" /><path
bordercolor="#666666" d="m 74.797528,31.305083 c 0,-6.160943 -4.994325,-11.155269 -11.155268,-11.155269 -6.130227,0 -11.101359,4.946683 -11.150255,11.064999 l -9.000067,1.203603 c -1.129004,-3.458478 -4.374972,-5.95909 -8.209576,-5.95909 -4.769905,0 -8.637734,3.867202 -8.637734,8.637734 0,3.824574 2.488074,7.063018 5.932134,8.198919 l -1.269425,9.24455 c -6.137749,0.02821 -11.103865,5.009371 -11.103865,11.152762 0,6.160942 4.994325,11.155895 11.155268,11.155895 6.147779,0 11.130822,-4.973638 11.152762,-11.115149 l 10.417436,-1.439935 c 1.139662,3.438419 4.374972,5.922103 8.195786,5.922103 4.769903,0 8.637732,-3.867202 8.637732,-8.637733 0,-3.967502 -2.678644,-7.301859 -6.323932,-8.314891 l 0.786104,-8.832065 c 5.889506,-0.305288 10.5729,-5.16233 10.5729,-11.126433 z M 52.506424,59.187928 42.075823,60.630371 c -1.05566,-3.697944 -3.965621,-6.6054 -7.66482,-7.657925 l 1.269425,-9.257087 c 4.440795,-0.203734 7.998945,-3.751856 8.216472,-8.18889 l 9.013859,-1.205483 c 1.090765,3.890396 4.23267,6.91445 8.19077,7.837838 l -0.786104,8.822035 c -4.26088,0.396186 -7.614044,3.888516 -7.809001,8.207069 z"
borderopacity="1.0" id="path2"
inkscape:pageopacity="0.0" style="fill:#0482d8;fill-opacity:1;stroke-width:0.62687665;opacity:0.3" /></svg>
inkscape:pageshadow="2"
inkscape:zoom="4.3194033"
inkscape:cx="79.987899"
inkscape:cy="64.129228"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
inkscape:snap-global="false"
inkscape:pagecheckerboard="0" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0.80272198,1.2346106)">
<rect
style="fill:#10b3d1;fill-opacity:1;stroke:none;stroke-width:1.53052;stroke-miterlimit:4;stroke-dasharray:none"
id="rect853"
width="31.75"
height="31.75"
x="-0.80272198"
y="-1.2346106" />
<path
id="path857"
style="fill:#f4962a;fill-opacity:1;stroke:#000000;stroke-width:1.48265;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.051525,3.9344041 A 10.434797,10.434797 0 0 0 4.6372555,14.368944 a 10.434797,10.434797 0 0 0 0,0.02075 v 0.03137 a 1.7839264,2.3625556 0 0 0 -0.9503056,-0.363423 1.7839264,2.3625556 0 0 0 -1.7838141,2.362493 1.7839264,2.3625556 0 0 0 1.7838141,2.362491 1.7839264,2.3625556 0 0 0 0.9503056,-0.363423 v 23.74268 H 25.507302 v -23.74268 a 1.7839264,2.3625556 0 0 0 0.950305,0.363423 1.7839264,2.3625556 0 0 0 1.783814,-2.362491 1.7839264,2.3625556 0 0 0 -1.783814,-2.362493 1.7839264,2.3625556 0 0 0 -0.950305,0.362941 v -0.05164 A 10.434797,10.434797 0 0 0 15.072278,3.9344041 a 10.434797,10.434797 0 0 0 -0.02075,0 z" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.900495;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path881-6"
cx="11.218504"
cy="13.292331"
r="1.3086123" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.900495;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path881-7"
cx="18.926052"
cy="13.292331"
r="1.3086123" />
<ellipse
style="fill:#f2f2f2;fill-opacity:1;stroke:#000000;stroke-width:0.88959;stroke-miterlimit:4;stroke-dasharray:none"
id="path917"
cx="15.072279"
cy="18.343904"
rx="7.1666903"
ry="4.0659413" />
<path
id="path957"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.88959;stroke-miterlimit:4;stroke-dasharray:none"
d="m 21.900069,17.108362 a 7.1666903,4.0659412 0 0 1 -6.82779,2.8304 7.1666903,4.0659412 0 0 1 -6.8277959,-2.830413" />
<path
id="path1003"
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.88959;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:transform-center-y="-0.79831289"
d="m 13.062455,16.997512 c 0.457808,-1.227486 1.336486,-2.475611 2.009822,-2.475611 0.673338,0 1.552013,1.248125 2.009824,2.475611" />
<path
style="fill:none;stroke:#000000;stroke-width:0.79375;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 24.842957,6.3249745 c -1.070225,-0.4344716 -2.309802,0.1182843 -2.464817,1.0590207 0,0 -1.627232,-1.9230616 1.219705,-3.5847621"
id="path1030"
sodipodi:nodetypes="ccc" />
</g>
</svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.8 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.2 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 81 B

Wyświetl plik

@ -0,0 +1,23 @@
{
"id": "106801667066418367",
"username": "benis911",
"acct": "benis911",
"display_name": "",
"locked": false,
"bot": false,
"discoverable": null,
"group": false,
"created_at": "2021-08-22T00:00:00.000Z",
"note": "",
"url": "https://mastodon.social/@benis911",
"avatar": "https://mastodon.social/avatars/original/missing.png",
"avatar_static": "https://mastodon.social/avatars/original/missing.png",
"header": "https://mastodon.social/headers/original/missing.png",
"header_static": "https://mastodon.social/headers/original/missing.png",
"followers_count": 1,
"following_count": 0,
"statuses_count": 5,
"last_status_at": "2022-02-23",
"emojis": [],
"fields": []
}

Wyświetl plik

@ -0,0 +1,123 @@
{
"uri": "mastodon.social",
"title": "Mastodon",
"short_description": "Server run by the main developers of the project <img draggable=\"false\" alt=\"🐘\" class=\"emojione\" src=\"https://mastodon.social/emoji/1f418.svg\" /> It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!",
"description": "Server run by the main developers of the project <img draggable=\"false\" alt=\"🐘\" class=\"emojione\" src=\"https://mastodon.social/emoji/1f418.svg\" /> It is not focused on any particular niche interest - everyone is welcome as long as you follow our code of conduct!",
"email": "staff@mastodon.social",
"version": "3.5.0rc1",
"urls": {
"streaming_api": "wss://mastodon.social"
},
"stats": {
"user_count": 635078,
"status_count": 34700866,
"domain_count": 21989
},
"thumbnail": "https://files.mastodon.social/site_uploads/files/000/000/001/original/vlcsnap-2018-08-27-16h43m11s127.png",
"languages": [
"en"
],
"registrations": true,
"approval_required": false,
"invites_enabled": true,
"configuration": {
"statuses": {
"max_characters": 500,
"max_media_attachments": 4,
"characters_reserved_per_url": 23
},
"media_attachments": {
"supported_mime_types": [
"image/jpeg",
"image/png",
"image/gif",
"video/webm",
"video/mp4",
"video/quicktime",
"video/ogg",
"audio/wave",
"audio/wav",
"audio/x-wav",
"audio/x-pn-wave",
"audio/ogg",
"audio/vorbis",
"audio/mpeg",
"audio/mp3",
"audio/webm",
"audio/flac",
"audio/aac",
"audio/m4a",
"audio/x-m4a",
"audio/mp4",
"audio/3gpp",
"video/x-ms-asf"
],
"image_size_limit": 10485760,
"image_matrix_limit": 16777216,
"video_size_limit": 41943040,
"video_frame_rate_limit": 60,
"video_matrix_limit": 2304000
},
"polls": {
"max_options": 4,
"max_characters_per_option": 50,
"min_expiration": 300,
"max_expiration": 2629746
}
},
"contact_account": {
"id": "1",
"username": "Gargron",
"acct": "Gargron",
"display_name": "Eugen",
"locked": false,
"bot": false,
"discoverable": true,
"group": false,
"created_at": "2016-03-16T00:00:00.000Z",
"note": "<p>Founder, CEO and lead developer <span class=\"h-card\"><a href=\"https://mastodon.social/@Mastodon\" class=\"u-url mention\">@<span>Mastodon</span></a></span>, Germany.</p>",
"url": "https://mastodon.social/@Gargron",
"avatar": "https://files.mastodon.social/accounts/avatars/000/000/001/original/ccb05a778962e171.png",
"avatar_static": "https://files.mastodon.social/accounts/avatars/000/000/001/original/ccb05a778962e171.png",
"header": "https://files.mastodon.social/accounts/headers/000/000/001/original/3b91c9965d00888b.jpeg",
"header_static": "https://files.mastodon.social/accounts/headers/000/000/001/original/3b91c9965d00888b.jpeg",
"followers_count": 99760,
"following_count": 274,
"statuses_count": 71657,
"last_status_at": "2022-03-17",
"emojis": [],
"fields": [
{
"name": "Patreon",
"value": "<a href=\"https://www.patreon.com/mastodon\" rel=\"me nofollow noopener noreferrer\" target=\"_blank\"><span class=\"invisible\">https://www.</span><span class=\"\">patreon.com/mastodon</span><span class=\"invisible\"></span></a>",
"verified_at": null
}
]
},
"rules": [
{
"id": "1",
"text": "Sexually explicit or violent media must be marked as sensitive when posting"
},
{
"id": "2",
"text": "No racism, sexism, homophobia, transphobia, xenophobia, or casteism"
},
{
"id": "3",
"text": "No incitement of violence or promotion of violent ideologies"
},
{
"id": "4",
"text": "No harassment, dogpiling or doxxing of other users"
},
{
"id": "5",
"text": "No content illegal in Germany"
},
{
"id": "7",
"text": "Do not share intentionally false or misleading information"
}
]
}

Wyświetl plik

@ -0,0 +1,119 @@
{
"account": {
"acct": "alex@fedibird.com",
"avatar": "https://gleasonator.com/images/avi.png",
"avatar_static": "https://gleasonator.com/images/avi.png",
"bot": false,
"created_at": "2022-01-24T21:25:37.000Z",
"display_name": "alex@fedibird.com",
"emojis": [],
"fields": [],
"followers_count": 2,
"following_count": 1,
"fqn": "alex@fedibird.com",
"header": "https://gleasonator.com/images/banner.png",
"header_static": "https://gleasonator.com/images/banner.png",
"id": "AFmHQ18XZ7Lco68MW8",
"last_status_at": "2022-03-16T22:07:53",
"locked": false,
"note": "<p></p>",
"pleroma": {
"accepts_chat_messages": null,
"also_known_as": [],
"ap_id": "https://fedibird.com/users/alex",
"background_image": null,
"birthday": "1993-07-03",
"deactivated": false,
"favicon": "https://gleasonator.com/proxy/HzfsidHss3CuA7aM2zxXN-tAjF8/aHR0cHM6Ly9mZWRpYmlyZC5jb20vZmF2aWNvbi5pY28/favicon.ico",
"hide_favorites": true,
"hide_followers": false,
"hide_followers_count": false,
"hide_follows": false,
"hide_follows_count": false,
"is_admin": false,
"is_confirmed": true,
"is_moderator": false,
"is_suggested": false,
"location": "Texas, USA",
"relationship": {},
"skip_thread_containment": false,
"tags": []
},
"source": {
"fields": [],
"note": "",
"pleroma": {
"actor_type": "Person",
"discoverable": false
},
"sensitive": false
},
"statuses_count": 5,
"url": "https://fedibird.com/@alex",
"username": "alex"
},
"created_at": "2022-03-17T00:08:48.000Z",
"id": "406814",
"pleroma": {
"is_muted": false,
"is_seen": true
},
"target": {
"acct": "benis911",
"avatar": "https://gleasonator.com/images/avi.png",
"avatar_static": "https://gleasonator.com/images/avi.png",
"bot": false,
"created_at": "2021-03-26T20:42:11.000Z",
"display_name": "benis911",
"emojis": [],
"fields": [],
"followers_count": 0,
"following_count": 0,
"fqn": "benis911@gleasonator.com",
"header": "https://media.gleasonator.com/fc595bbbcf5aabefecd1c2adfe5b7f5457db59847992881668653a0338ba25bd.jpg",
"header_static": "https://media.gleasonator.com/fc595bbbcf5aabefecd1c2adfe5b7f5457db59847992881668653a0338ba25bd.jpg",
"id": "A5c5LK7EJTFR0u26Pg",
"last_status_at": "2022-03-16T22:01:57",
"locked": false,
"note": "hello world 2",
"pleroma": {
"accepts_chat_messages": true,
"also_known_as": [
"https://gleasonator.com/users/alex",
"https://poa.st/users/alex",
"https://fedibird.com/users/alex"
],
"ap_id": "https://gleasonator.com/users/benis911",
"background_image": null,
"birthday": "2000-01-25",
"deactivated": false,
"favicon": "https://gleasonator.com/favicon.png",
"hide_favorites": true,
"hide_followers": true,
"hide_followers_count": true,
"hide_follows": true,
"hide_follows_count": true,
"is_admin": false,
"is_confirmed": true,
"is_moderator": false,
"is_suggested": false,
"location": null,
"relationship": {},
"skip_thread_containment": false,
"tags": []
},
"source": {
"fields": [],
"note": "hello world 2",
"pleroma": {
"actor_type": "Person",
"discoverable": false
},
"sensitive": false
},
"statuses_count": 172,
"url": "https://gleasonator.com/users/benis911",
"username": "benis911"
},
"type": "move"
}

Wyświetl plik

@ -0,0 +1,229 @@
{
"account": {
"acct": "alex",
"avatar": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
"avatar_static": "https://media.gleasonator.com/6d64aecb17348b23aaff78db4687b9476cb0da1c07cc6a819c2e6ec7144c18b1.png",
"bot": false,
"created_at": "2020-01-08T01:25:43.000Z",
"display_name": "Alex Gleason",
"emojis": [],
"fields": [
{
"name": "Website",
"value": "<a href=\"https://alexgleason.me\" rel=\"ugc\">https://alexgleason.me</a>"
},
{
"name": "Soapbox",
"value": "<a href=\"https://soapbox.pub\" rel=\"ugc\">https://soapbox.pub</a>"
},
{
"name": "Email",
"value": "alex@alexgleason.me"
},
{
"name": "Gender identity",
"value": "Soyboy"
},
{
"name": "Donate (PayPal)",
"value": "<a href=\"https://paypal.me/gleasonator\" rel=\"ugc\">https://paypal.me/gleasonator</a>"
},
{
"name": "$BTC",
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
},
{
"name": "$ETH",
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
},
{
"name": "$DOGE",
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
},
{
"name": "$XMR",
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
}
],
"follow_requests_count": 0,
"followers_count": 2489,
"following_count": 1586,
"fqn": "alex@gleasonator.com",
"header": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
"header_static": "https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png",
"id": "9v5bmRalQvjOy0ECcC",
"last_status_at": "2022-03-16T21:57:17",
"locked": false,
"note": "I create Fediverse software that empowers people online.<br/><br/>I&#39;m vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
"pleroma": {
"accepts_chat_messages": true,
"accepts_email_list": true,
"allow_following_move": true,
"also_known_as": [
"https://mitra.social/users/alex"
],
"ap_id": "https://gleasonator.com/users/alex",
"background_image": null,
"birthday": "1993-07-03",
"deactivated": false,
"email": "alex@alexgleason.me",
"favicon": "https://gleasonator.com/favicon.png",
"hide_favorites": true,
"hide_followers": false,
"hide_followers_count": false,
"hide_follows": false,
"hide_follows_count": false,
"is_admin": true,
"is_confirmed": true,
"is_moderator": false,
"is_suggested": true,
"location": null,
"notification_settings": {
"block_from_strangers": false,
"hide_notification_contents": false
},
"relationship": {},
"skip_thread_containment": false,
"tags": [],
"unread_conversation_count": 392,
"unread_notifications_count": 2
},
"source": {
"fields": [
{
"name": "Website",
"value": "https://alexgleason.me"
},
{
"name": "Soapbox",
"value": "https://soapbox.pub"
},
{
"name": "Email",
"value": "alex@alexgleason.me"
},
{
"name": "Gender identity",
"value": "Soyboy"
},
{
"name": "Donate (PayPal)",
"value": "https://paypal.me/gleasonator"
},
{
"name": "$BTC",
"value": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n"
},
{
"name": "$ETH",
"value": "0xAc9aB5Fc04Dc1cB1789Af75b523Bd23C70B2D717"
},
{
"name": "$DOGE",
"value": "D5zVZs6jrRakaPVGiErkQiHt9sayzm6V5D"
},
{
"name": "$XMR",
"value": "45JDCLrjJ4bgVUSbbs2yjy9m5Mf4VLPW8fG7jw9sq5u69rXZZopQogZNeyYkMBnXpkaip4p4QwaaJNhdTotPa9g44DBCzdK"
}
],
"note": "I create Fediverse software that empowers people online.\r\n\r\nI'm vegan btw\r\n\r\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.",
"pleroma": {
"actor_type": "Person",
"discoverable": false,
"no_rich_text": false,
"show_birthday": true,
"show_role": true
},
"privacy": "public",
"sensitive": false
},
"statuses_count": 23695,
"url": "https://gleasonator.com/users/alex",
"username": "alex"
},
"application": {
"name": "Soapbox FE",
"website": "https://soapbox.pub/"
},
"bookmarked": false,
"card": null,
"content": "<p>I am going to delete this post for testing purposes</p>",
"created_at": "2022-03-16T21:57:16.000Z",
"emojis": [],
"favourited": false,
"favourites_count": 3,
"id": "AHU2RrX0wdcwzCYjFQ",
"in_reply_to_account_id": null,
"in_reply_to_id": null,
"language": null,
"media_attachments": [
{
"blurhash": "eWGlL@?b~q%MRj4nt7IUof%M%MIURjRjIUM{IUM{Rjayxut7j[j[xu",
"description": "",
"id": "508107650",
"meta": {
"original": {
"aspect": 1,
"height": 1024,
"width": 1024
}
},
"pleroma": {
"mime_type": "image/png"
},
"preview_url": "https://media.gleasonator.com/2b9ddcd8b27cad786fd34bc2cfe02c1b63aa1b8e7b8d72379b5c9375fb61f199.png",
"remote_url": "https://media.gleasonator.com/2b9ddcd8b27cad786fd34bc2cfe02c1b63aa1b8e7b8d72379b5c9375fb61f199.png",
"text_url": "https://media.gleasonator.com/2b9ddcd8b27cad786fd34bc2cfe02c1b63aa1b8e7b8d72379b5c9375fb61f199.png",
"type": "image",
"url": "https://media.gleasonator.com/2b9ddcd8b27cad786fd34bc2cfe02c1b63aa1b8e7b8d72379b5c9375fb61f199.png"
}
],
"mentions": [],
"muted": false,
"pinned": false,
"pleroma": {
"content": {
"text/plain": "I am going to delete this post for testing purposes"
},
"content_type": "text/markdown",
"conversation_id": "AHU2RrUB7BMIqPESpM",
"direct_conversation_id": null,
"emoji_reactions": [
{
"count": 1,
"me": false,
"name": "😭"
},
{
"count": 1,
"me": false,
"name": "❔"
}
],
"expires_at": null,
"in_reply_to_account_acct": null,
"local": true,
"parent_visible": false,
"pinned_at": null,
"quote": null,
"quote_url": null,
"quote_visible": false,
"spoiler_text": {
"text/plain": ""
},
"thread_muted": false
},
"poll": null,
"reblog": null,
"reblogged": false,
"reblogs_count": 1,
"replies_count": 2,
"sensitive": false,
"spoiler_text": "",
"tags": [],
"text": "I am going to delete this post for testing purposes",
"uri": "https://gleasonator.com/objects/205ec868-d28d-4668-a56a-33321f7e285e",
"url": "https://gleasonator.com/notice/AHU2RrX0wdcwzCYjFQ",
"visibility": "public"
}

Wyświetl plik

@ -1,26 +0,0 @@
import MockAdapter from 'axios-mock-adapter';
const api = jest.requireActual('../api');
let mocks = [];
export const __stub = func => mocks.push(func);
export const __clear = () => mocks = [];
const setupMock = axios => {
const mock = new MockAdapter(axios);
mocks.map(func => func(mock));
};
export const staticClient = api.staticClient;
export const baseClient = (...params) => {
const axios = api.baseClient(...params);
setupMock(axios);
return axios;
};
export default (...params) => {
const axios = api.default(...params);
setupMock(axios);
return axios;
};

Wyświetl plik

@ -0,0 +1,28 @@
import { jest } from '@jest/globals';
import { AxiosInstance } from 'axios';
import MockAdapter from 'axios-mock-adapter';
const api = jest.requireActual('../api') as Record<string, Function>;
let mocks: Array<Function> = [];
export const __stub = (func: Function) => mocks.push(func);
export const __clear = (): Function[] => mocks = [];
const setupMock = (axios: AxiosInstance) => {
const mock = new MockAdapter(axios);
mocks.map(func => func(mock));
};
export const staticClient = api.staticClient;
export const baseClient = (...params: any[]) => {
const axios = api.baseClient(...params);
setupMock(axios);
return axios;
};
export default (...params: any[]) => {
const axios = api.default(...params);
setupMock(axios);
return axios;
};

Wyświetl plik

@ -1,8 +1,6 @@
import { Map as ImmutableMap } from 'immutable';
import { STATUSES_IMPORT } from 'soapbox/actions/importer'; import { STATUSES_IMPORT } from 'soapbox/actions/importer';
import { __stub } from 'soapbox/api'; import { __stub } from 'soapbox/api';
import { mockStore } from 'soapbox/test_helpers'; import { mockStore, rootState } from 'soapbox/test_helpers';
import { fetchContext } from '../statuses'; import { fetchContext } from '../statuses';
@ -15,7 +13,7 @@ describe('fetchContext()', () => {
.reply(200, statuses); .reply(200, statuses);
}); });
const store = mockStore(ImmutableMap()); const store = mockStore(rootState);
store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(context => { store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(context => {
const actions = store.getActions(); const actions = store.getActions();

Wyświetl plik

@ -6,11 +6,10 @@
* @see module:soapbox/actions/oauth * @see module:soapbox/actions/oauth
*/ */
import { Map as ImmutableMap, fromJS } from 'immutable';
import { createApp } from 'soapbox/actions/apps'; import { createApp } from 'soapbox/actions/apps';
import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth'; import { authLoggedIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
import { obtainOAuthToken } from 'soapbox/actions/oauth'; import { obtainOAuthToken } from 'soapbox/actions/oauth';
import { normalizeInstance } from 'soapbox/normalizers';
import { parseBaseURL } from 'soapbox/utils/auth'; import { parseBaseURL } from 'soapbox/utils/auth';
import sourceCode from 'soapbox/utils/code'; import sourceCode from 'soapbox/utils/code';
import { getWalletAndSign } from 'soapbox/utils/ethereum'; import { getWalletAndSign } from 'soapbox/utils/ethereum';
@ -22,12 +21,12 @@ import { baseClient } from '../api';
const fetchExternalInstance = baseURL => { const fetchExternalInstance = baseURL => {
return baseClient(null, baseURL) return baseClient(null, baseURL)
.get('/api/v1/instance') .get('/api/v1/instance')
.then(({ data: instance }) => fromJS(instance)) .then(({ data: instance }) => normalizeInstance(instance))
.catch(error => { .catch(error => {
if (error.response?.status === 401) { if (error.response?.status === 401) {
// Authenticated fetch is enabled. // Authenticated fetch is enabled.
// Continue with a limited featureset. // Continue with a limited featureset.
return ImmutableMap({ version: '0.0.0' }); return normalizeInstance({});
} else { } else {
throw error; throw error;
} }

Wyświetl plik

@ -1,5 +1,5 @@
import { isLoggedIn } from 'soapbox/utils/auth'; import { isLoggedIn } from 'soapbox/utils/auth';
import { getFeatures } from 'soapbox/utils/features'; import { getFeatures, parseVersion } from 'soapbox/utils/features';
import { shouldHaveCard } from 'soapbox/utils/status'; import { shouldHaveCard } from 'soapbox/utils/status';
import api from '../api'; import api from '../api';
@ -99,8 +99,7 @@ export function fetchStatus(id) {
export function redraft(status, raw_text, content_type) { export function redraft(status, raw_text, content_type) {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const { instance } = getState();
const instance = state.get('instance');
const { explicitAddressing } = getFeatures(instance); const { explicitAddressing } = getFeatures(instance);
dispatch({ dispatch({
@ -109,6 +108,7 @@ export function redraft(status, raw_text, content_type) {
raw_text, raw_text,
explicitAddressing, explicitAddressing,
content_type, content_type,
v: parseVersion(instance.version),
}); });
}; };
} }

Wyświetl plik

@ -16,10 +16,10 @@ export const SUGGESTIONS_V2_FETCH_REQUEST = 'SUGGESTIONS_V2_FETCH_REQUEST';
export const SUGGESTIONS_V2_FETCH_SUCCESS = 'SUGGESTIONS_V2_FETCH_SUCCESS'; export const SUGGESTIONS_V2_FETCH_SUCCESS = 'SUGGESTIONS_V2_FETCH_SUCCESS';
export const SUGGESTIONS_V2_FETCH_FAIL = 'SUGGESTIONS_V2_FETCH_FAIL'; export const SUGGESTIONS_V2_FETCH_FAIL = 'SUGGESTIONS_V2_FETCH_FAIL';
export function fetchSuggestionsV1() { export function fetchSuggestionsV1(params = {}) {
return (dispatch, getState) => { return (dispatch, getState) => {
dispatch({ type: SUGGESTIONS_FETCH_REQUEST, skipLoading: true }); dispatch({ type: SUGGESTIONS_FETCH_REQUEST, skipLoading: true });
return api(getState).get('/api/v1/suggestions').then(({ data: accounts }) => { return api(getState).get('/api/v1/suggestions', { params }).then(({ data: accounts }) => {
dispatch(importFetchedAccounts(accounts)); dispatch(importFetchedAccounts(accounts));
dispatch({ type: SUGGESTIONS_FETCH_SUCCESS, accounts, skipLoading: true }); dispatch({ type: SUGGESTIONS_FETCH_SUCCESS, accounts, skipLoading: true });
return accounts; return accounts;
@ -30,10 +30,10 @@ export function fetchSuggestionsV1() {
}; };
} }
export function fetchSuggestionsV2() { export function fetchSuggestionsV2(params = {}) {
return (dispatch, getState) => { return (dispatch, getState) => {
dispatch({ type: SUGGESTIONS_V2_FETCH_REQUEST, skipLoading: true }); dispatch({ type: SUGGESTIONS_V2_FETCH_REQUEST, skipLoading: true });
return api(getState).get('/api/v2/suggestions').then(({ data: suggestions }) => { return api(getState).get('/api/v2/suggestions', { params }).then(({ data: suggestions }) => {
const accounts = suggestions.map(({ account }) => account); const accounts = suggestions.map(({ account }) => account);
dispatch(importFetchedAccounts(accounts)); dispatch(importFetchedAccounts(accounts));
dispatch({ type: SUGGESTIONS_V2_FETCH_SUCCESS, suggestions, skipLoading: true }); dispatch({ type: SUGGESTIONS_V2_FETCH_SUCCESS, suggestions, skipLoading: true });
@ -45,21 +45,21 @@ export function fetchSuggestionsV2() {
}; };
} }
export function fetchSuggestions() { export function fetchSuggestions(params = { limit: 50 }) {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const state = getState();
const instance = state.get('instance'); const instance = state.get('instance');
const features = getFeatures(instance); const features = getFeatures(instance);
if (features.suggestionsV2) { if (features.suggestionsV2) {
dispatch(fetchSuggestionsV2()) dispatch(fetchSuggestionsV2(params))
.then(suggestions => { .then(suggestions => {
const accountIds = suggestions.map(({ account }) => account.id); const accountIds = suggestions.map(({ account }) => account.id);
dispatch(fetchRelationships(accountIds)); dispatch(fetchRelationships(accountIds));
}) })
.catch(() => {}); .catch(() => {});
} else if (features.suggestions) { } else if (features.suggestions) {
dispatch(fetchSuggestionsV1()) dispatch(fetchSuggestionsV1(params))
.then(accounts => { .then(accounts => {
const accountIds = accounts.map(({ id }) => id); const accountIds = accounts.map(({ id }) => id);
dispatch(fetchRelationships(accountIds)); dispatch(fetchRelationships(accountIds));

Wyświetl plik

@ -1,12 +1,12 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import DatePicker from 'react-datepicker';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import 'react-datepicker/dist/react-datepicker.css';
import IconButton from 'soapbox/components/icon_button'; import IconButton from 'soapbox/components/icon_button';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { getFeatures } from 'soapbox/utils/features'; import { getFeatures } from 'soapbox/utils/features';
const messages = defineMessages({ const messages = defineMessages({
@ -112,16 +112,18 @@ class BirthdayInput extends ImmutablePureComponent {
</div> </div>
)} )}
<div className='datepicker__input'> <div className='datepicker__input'>
<DatePicker <BundleContainer fetchComponent={DatePicker}>
selected={value} {Component => (<Component
wrapperClassName='react-datepicker-wrapper' selected={value}
onChange={onChange} wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.birthdayPlaceholder)} onChange={onChange}
minDate={new Date('1900-01-01')} placeholderText={intl.formatMessage(messages.birthdayPlaceholder)}
maxDate={maxDate} minDate={new Date('1900-01-01')}
required={required} maxDate={maxDate}
renderCustomHeader={this.renderHeader} required={required}
/> renderCustomHeader={this.renderHeader}
/>)}
</BundleContainer>
</div> </div>
</div> </div>
); );

Wyświetl plik

@ -0,0 +1,4 @@
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
export default DatePicker;

Wyświetl plik

@ -3,12 +3,12 @@
import classNames from 'classnames'; import classNames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import DatePicker from 'react-datepicker';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import 'react-datepicker/dist/react-datepicker.css';
import IconButton from 'soapbox/components/icon_button'; import IconButton from 'soapbox/components/icon_button';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { setSchedule, removeSchedule } from '../../../actions/compose'; import { setSchedule, removeSchedule } from '../../../actions/compose';
@ -104,18 +104,20 @@ class ScheduleForm extends React.Component {
<FormattedMessage id='datepicker.hint' defaultMessage='Scheduled to post at…' /> <FormattedMessage id='datepicker.hint' defaultMessage='Scheduled to post at…' />
</div> </div>
<div className='datepicker__input'> <div className='datepicker__input'>
<DatePicker <BundleContainer fetchComponent={DatePicker}>
selected={scheduledAt} {Component => (<Component
showTimeSelect selected={scheduledAt}
dateFormat='MMMM d, yyyy h:mm aa' showTimeSelect
timeIntervals={15} dateFormat='MMMM d, yyyy h:mm aa'
wrapperClassName='react-datepicker-wrapper' timeIntervals={15}
onChange={this.setSchedule} wrapperClassName='react-datepicker-wrapper'
placeholderText={this.props.intl.formatMessage(messages.schedule)} onChange={this.setSchedule}
filterDate={this.isCurrentOrFutureDate} placeholderText={this.props.intl.formatMessage(messages.schedule)}
filterTime={this.isFiveMinutesFromNow} filterDate={this.isCurrentOrFutureDate}
ref={this.setRef} filterTime={this.isFiveMinutesFromNow}
/> ref={this.setRef}
/>)}
</BundleContainer>
<div className='datepicker__cancel'> <div className='datepicker__cancel'>
<IconButton title={intl.formatMessage(messages.remove)} src={require('@tabler/icons/icons/x.svg')} onClick={this.handleRemove} /> <IconButton title={intl.formatMessage(messages.remove)} src={require('@tabler/icons/icons/x.svg')} onClick={this.handleRemove} />
</div> </div>

Wyświetl plik

@ -465,3 +465,7 @@ export function CreateApp() {
export function SettingsStore() { export function SettingsStore() {
return import(/* webpackChunkName: "features/developers" */'../../developers/settings_store'); return import(/* webpackChunkName: "features/developers" */'../../developers/settings_store');
} }
export function DatePicker() {
return import(/* webpackChunkName: "date_picker" */'../../birthdays/date_picker');
}

Wyświetl plik

@ -3,25 +3,27 @@ import { Record as ImmutableRecord, fromJS } from 'immutable';
import { normalizeAccount } from '../account'; import { normalizeAccount } from '../account';
const AVATAR_MISSING = require('images/avatar-missing.png'); const AVATAR_MISSING = require('images/avatar-missing.png');
const HEADER_MISSING = require('images/header-missing.png');
describe('normalizeAccount()', () => { describe('normalizeAccount()', () => {
it('adds base fields', () => { it('adds base fields', () => {
const account = fromJS({}); const account = {};
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(ImmutableRecord.isRecord(result)).toBe(true); expect(ImmutableRecord.isRecord(result)).toBe(true);
expect(result.acct).toEqual(''); expect(result.acct).toEqual('');
expect(result.note).toEqual(''); expect(result.note).toEqual('');
expect(result.avatar).toEqual(AVATAR_MISSING); expect(result.avatar).toEqual(AVATAR_MISSING);
expect(result.header_static).toEqual(HEADER_MISSING);
}); });
it('normalizes a mention', () => { it('normalizes a mention', () => {
const mention = fromJS({ const mention = {
acct: 'NEETzsche@iddqd.social', acct: 'NEETzsche@iddqd.social',
id: '9v5bw7hEGBPc9nrpzc', id: '9v5bw7hEGBPc9nrpzc',
url: 'https://iddqd.social/users/NEETzsche', url: 'https://iddqd.social/users/NEETzsche',
username: 'NEETzsche', username: 'NEETzsche',
}); };
const result = normalizeAccount(mention); const result = normalizeAccount(mention);
expect(result.emojis).toEqual(fromJS([])); expect(result.emojis).toEqual(fromJS([]));
@ -32,21 +34,21 @@ describe('normalizeAccount()', () => {
}); });
it('normalizes Fedibird birthday', () => { it('normalizes Fedibird birthday', () => {
const account = fromJS(require('soapbox/__fixtures__/fedibird-account.json')); const account = require('soapbox/__fixtures__/fedibird-account.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.birthday).toEqual('1993-07-03'); expect(result.birthday).toEqual('1993-07-03');
}); });
it('normalizes Pleroma birthday', () => { it('normalizes Pleroma birthday', () => {
const account = fromJS(require('soapbox/__fixtures__/pleroma-account.json')); const account = require('soapbox/__fixtures__/pleroma-account.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.birthday).toEqual('1993-07-03'); expect(result.birthday).toEqual('1993-07-03');
}); });
it('normalizes Pleroma legacy fields', () => { it('normalizes Pleroma legacy fields', () => {
const account = fromJS(require('soapbox/__fixtures__/pleroma-2.2.2-account.json')); const account = require('soapbox/__fixtures__/pleroma-2.2.2-account.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.getIn(['pleroma', 'is_active'])).toBe(true); expect(result.getIn(['pleroma', 'is_active'])).toBe(true);
@ -57,7 +59,7 @@ describe('normalizeAccount()', () => {
}); });
it('prefers new Pleroma fields', () => { it('prefers new Pleroma fields', () => {
const account = fromJS(require('soapbox/__fixtures__/pleroma-account.json')); const account = require('soapbox/__fixtures__/pleroma-account.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.getIn(['pleroma', 'is_active'])).toBe(true); expect(result.getIn(['pleroma', 'is_active'])).toBe(true);
@ -66,76 +68,82 @@ describe('normalizeAccount()', () => {
}); });
it('normalizes a verified Pleroma user', () => { it('normalizes a verified Pleroma user', () => {
const account = fromJS(require('soapbox/__fixtures__/mk.json')); const account = require('soapbox/__fixtures__/mk.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.verified).toBe(true); expect(result.verified).toBe(true);
}); });
it('normalizes an unverified Pleroma user', () => { it('normalizes an unverified Pleroma user', () => {
const account = fromJS(require('soapbox/__fixtures__/pleroma-account.json')); const account = require('soapbox/__fixtures__/pleroma-account.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.verified).toBe(false); expect(result.verified).toBe(false);
}); });
it('normalizes a verified Truth Social user', () => { it('normalizes a verified Truth Social user', () => {
const account = fromJS(require('soapbox/__fixtures__/realDonaldTrump.json')); const account = require('soapbox/__fixtures__/realDonaldTrump.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.verified).toBe(true); expect(result.verified).toBe(true);
}); });
it('normalizes Fedibird location', () => { it('normalizes Fedibird location', () => {
const account = fromJS(require('soapbox/__fixtures__/fedibird-account.json')); const account = require('soapbox/__fixtures__/fedibird-account.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.location).toBe('Texas, USA'); expect(result.location).toBe('Texas, USA');
}); });
it('normalizes Truth Social location', () => { it('normalizes Truth Social location', () => {
const account = fromJS(require('soapbox/__fixtures__/truthsocial-account.json')); const account = require('soapbox/__fixtures__/truthsocial-account.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.location).toBe('Texas'); expect(result.location).toBe('Texas');
}); });
it('normalizes Truth Social website', () => {
const account = require('soapbox/__fixtures__/truthsocial-account.json');
const result = normalizeAccount(account);
expect(result.website).toBe('https://soapbox.pub');
});
it('sets display_name from username', () => { it('sets display_name from username', () => {
const account = fromJS({ username: 'alex' }); const account = { username: 'alex' };
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.display_name).toBe('alex'); expect(result.display_name).toBe('alex');
}); });
it('sets display_name from acct', () => { it('sets display_name from acct', () => {
const account = fromJS({ acct: 'alex@gleasonator.com' }); const account = { acct: 'alex@gleasonator.com' };
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.display_name).toBe('alex'); expect(result.display_name).toBe('alex');
}); });
it('overrides a whitespace display_name', () => { it('overrides a whitespace display_name', () => {
const account = fromJS({ username: 'alex', display_name: ' ' }); const account = { username: 'alex', display_name: ' ' };
const result = normalizeAccount(account); const result = normalizeAccount(account);
expect(result.display_name).toBe('alex'); expect(result.display_name).toBe('alex');
}); });
it('emojifies display name as `display_name_html`', () => { it('emojifies display name as `display_name_html`', () => {
const account = fromJS(require('soapbox/__fixtures__/account-with-emojis.json')); const account = require('soapbox/__fixtures__/account-with-emojis.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
const expected = 'Alex Gleason <img draggable="false" class="emojione" alt="😂" title=":joy:" src="/packs/emoji/1f602.svg" /> <img draggable="false" class="emojione" alt=":soapbox:" title=":soapbox:" src="https://gleasonator.com/emoji/Gleasonator/soapbox.png" /> <img draggable="false" class="emojione" alt=":ablobcatrainbow:" title=":ablobcatrainbow:" src="https://gleasonator.com/emoji/blobcat/ablobcatrainbow.png" />'; const expected = 'Alex Gleason <img draggable="false" class="emojione" alt="😂" title=":joy:" src="/packs/emoji/1f602.svg" /> <img draggable="false" class="emojione" alt=":soapbox:" title=":soapbox:" src="https://gleasonator.com/emoji/Gleasonator/soapbox.png" /> <img draggable="false" class="emojione" alt=":ablobcatrainbow:" title=":ablobcatrainbow:" src="https://gleasonator.com/emoji/blobcat/ablobcatrainbow.png" />';
expect(result.display_name_html).toBe(expected); expect(result.display_name_html).toBe(expected);
}); });
it('emojifies note as `note_emojified`', () => { it('emojifies note as `note_emojified`', () => {
const account = fromJS(require('soapbox/__fixtures__/account-with-emojis.json')); const account = require('soapbox/__fixtures__/account-with-emojis.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
const expected = 'I create Fediverse software that empowers people online. <img draggable="false" class="emojione" alt=":soapbox:" title=":soapbox:" src="https://gleasonator.com/emoji/Gleasonator/soapbox.png" /><br/><br/>I&#39;m vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.'; const expected = 'I create Fediverse software that empowers people online. <img draggable="false" class="emojione" alt=":soapbox:" title=":soapbox:" src="https://gleasonator.com/emoji/Gleasonator/soapbox.png" /><br/><br/>I&#39;m vegan btw<br/><br/>Note: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.';
expect(result.note_emojified).toBe(expected); expect(result.note_emojified).toBe(expected);
}); });
it('unescapes HTML note as `note_plain`', () => { it('unescapes HTML note as `note_plain`', () => {
const account = fromJS(require('soapbox/__fixtures__/account-with-emojis.json')); const account = require('soapbox/__fixtures__/account-with-emojis.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
const expected = 'I create Fediverse software that empowers people online. :soapbox:\n\nI\'m vegan btw\n\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.'; const expected = 'I create Fediverse software that empowers people online. :soapbox:\n\nI\'m vegan btw\n\nNote: If you have a question for me, please tag me publicly. This gives the opportunity for others to chime in, and bystanders to learn.';
expect(result.note_plain).toBe(expected); expect(result.note_plain).toBe(expected);
}); });
it('emojifies custom profile field', () => { it('emojifies custom profile field', () => {
const account = fromJS(require('soapbox/__fixtures__/account-with-emojis.json')); const account = require('soapbox/__fixtures__/account-with-emojis.json');
const result = normalizeAccount(account); const result = normalizeAccount(account);
const field = result.fields.get(1); const field = result.fields.get(1);
@ -143,4 +151,21 @@ describe('normalizeAccount()', () => {
expect(field.value_emojified).toBe('<a href="https://soapbox.pub" rel="ugc">https://soapbox.pub</a> <img draggable="false" class="emojione" alt=":soapbox:" title=":soapbox:" src="https://gleasonator.com/emoji/Gleasonator/soapbox.png" />'); expect(field.value_emojified).toBe('<a href="https://soapbox.pub" rel="ugc">https://soapbox.pub</a> <img draggable="false" class="emojione" alt=":soapbox:" title=":soapbox:" src="https://gleasonator.com/emoji/Gleasonator/soapbox.png" />');
expect(field.value_plain).toBe('https://soapbox.pub :soapbox:'); expect(field.value_plain).toBe('https://soapbox.pub :soapbox:');
}); });
it('adds default avatar and banner to GoToSocial account', () => {
const account = require('soapbox/__fixtures__/gotosocial-account.json');
const result = normalizeAccount(account);
expect(result.avatar).toEqual(AVATAR_MISSING);
expect(result.avatar_static).toEqual(AVATAR_MISSING);
expect(result.header).toEqual(HEADER_MISSING);
expect(result.header_static).toEqual(HEADER_MISSING);
});
it('adds fqn to Mastodon account', () => {
const account = require('soapbox/__fixtures__/mastodon-account.json');
const result = normalizeAccount(account);
expect(result.fqn).toEqual('benis911@mastodon.social');
});
}); });

Wyświetl plik

@ -1,10 +1,10 @@
import { Record as ImmutableRecord, fromJS } from 'immutable'; import { Record as ImmutableRecord } from 'immutable';
import { normalizeAttachment } from '../attachment'; import { normalizeAttachment } from '../attachment';
describe('normalizeAttachment()', () => { describe('normalizeAttachment()', () => {
it('adds base fields', () => { it('adds base fields', () => {
const attachment = fromJS({}); const attachment = {};
const result = normalizeAttachment(attachment); const result = normalizeAttachment(attachment);
expect(ImmutableRecord.isRecord(result)).toBe(true); expect(ImmutableRecord.isRecord(result)).toBe(true);
@ -13,7 +13,7 @@ describe('normalizeAttachment()', () => {
}); });
it('infers preview_url from url', () => { it('infers preview_url from url', () => {
const attachment = fromJS({ url: 'https://site.fedi/123.png' }); const attachment = { url: 'https://site.fedi/123.png' };
const result = normalizeAttachment(attachment); const result = normalizeAttachment(attachment);
expect(result.preview_url).toEqual('https://site.fedi/123.png'); expect(result.preview_url).toEqual('https://site.fedi/123.png');

Wyświetl plik

@ -1,10 +1,10 @@
import { Record as ImmutableRecord, fromJS } from 'immutable'; import { Record as ImmutableRecord } from 'immutable';
import { normalizeCard } from '../card'; import { normalizeCard } from '../card';
describe('normalizeCard()', () => { describe('normalizeCard()', () => {
it('adds base fields', () => { it('adds base fields', () => {
const card = fromJS({}); const card = {};
const result = normalizeCard(card); const result = normalizeCard(card);
expect(ImmutableRecord.isRecord(result)).toBe(true); expect(ImmutableRecord.isRecord(result)).toBe(true);

Wyświetl plik

@ -59,7 +59,7 @@ describe('normalizeInstance()', () => {
}); });
it('normalizes Pleroma instance with Mastodon configuration format', () => { it('normalizes Pleroma instance with Mastodon configuration format', () => {
const instance = fromJS(require('soapbox/__fixtures__/pleroma-instance.json')); const instance = require('soapbox/__fixtures__/pleroma-instance.json');
const expected = { const expected = {
configuration: { configuration: {
@ -81,7 +81,7 @@ describe('normalizeInstance()', () => {
}); });
it('normalizes Mastodon instance with retained configuration', () => { it('normalizes Mastodon instance with retained configuration', () => {
const instance = fromJS(require('soapbox/__fixtures__/mastodon-instance.json')); const instance = require('soapbox/__fixtures__/mastodon-instance.json');
const expected = { const expected = {
configuration: { configuration: {
@ -111,7 +111,7 @@ describe('normalizeInstance()', () => {
}); });
it('normalizes Mastodon 3.0.0 instance with default configuration', () => { it('normalizes Mastodon 3.0.0 instance with default configuration', () => {
const instance = fromJS(require('soapbox/__fixtures__/mastodon-3.0.0-instance.json')); const instance = require('soapbox/__fixtures__/mastodon-3.0.0-instance.json');
const expected = { const expected = {
configuration: { configuration: {
@ -133,18 +133,18 @@ describe('normalizeInstance()', () => {
}); });
it('normalizes Fedibird instance', () => { it('normalizes Fedibird instance', () => {
const instance = fromJS(require('soapbox/__fixtures__/fedibird-instance.json')); const instance = require('soapbox/__fixtures__/fedibird-instance.json');
const result = normalizeInstance(instance); const result = normalizeInstance(instance);
// Sets description_limit // Sets description_limit
expect(result.description_limit).toEqual(1500); expect(result.description_limit).toEqual(1500);
// Preserves fedibird_capabilities // Preserves fedibird_capabilities
expect(result.fedibird_capabilities).toEqual(instance.get('fedibird_capabilities')); expect(result.fedibird_capabilities).toEqual(fromJS(instance.fedibird_capabilities));
}); });
it('normalizes Mitra instance', () => { it('normalizes Mitra instance', () => {
const instance = fromJS(require('soapbox/__fixtures__/mitra-instance.json')); const instance = require('soapbox/__fixtures__/mitra-instance.json');
const result = normalizeInstance(instance); const result = normalizeInstance(instance);
// Adds configuration and description_limit // Adds configuration and description_limit
@ -153,7 +153,7 @@ describe('normalizeInstance()', () => {
}); });
it('normalizes GoToSocial instance', () => { it('normalizes GoToSocial instance', () => {
const instance = fromJS(require('soapbox/__fixtures__/gotosocial-instance.json')); const instance = require('soapbox/__fixtures__/gotosocial-instance.json');
const result = normalizeInstance(instance); const result = normalizeInstance(instance);
// Normalizes max_toot_chars // Normalizes max_toot_chars
@ -166,7 +166,7 @@ describe('normalizeInstance()', () => {
}); });
it('normalizes Friendica instance', () => { it('normalizes Friendica instance', () => {
const instance = fromJS(require('soapbox/__fixtures__/friendica-instance.json')); const instance = require('soapbox/__fixtures__/friendica-instance.json');
const result = normalizeInstance(instance); const result = normalizeInstance(instance);
// Normalizes max_toot_chars // Normalizes max_toot_chars
@ -177,4 +177,11 @@ describe('normalizeInstance()', () => {
expect(result.get('configuration') instanceof ImmutableMap).toBe(true); expect(result.get('configuration') instanceof ImmutableMap).toBe(true);
expect(result.get('description_limit')).toBe(1500); expect(result.get('description_limit')).toBe(1500);
}); });
it('normalizes a Mastodon RC version', () => {
const instance = require('soapbox/__fixtures__/mastodon-instance-rc.json');
const result = normalizeInstance(instance);
expect(result.version).toEqual('3.5.0-rc1');
});
}); });

Wyświetl plik

@ -1,10 +1,10 @@
import { Record as ImmutableRecord, fromJS } from 'immutable'; import { Record as ImmutableRecord } from 'immutable';
import { normalizeMention } from '../mention'; import { normalizeMention } from '../mention';
describe('normalizeMention()', () => { describe('normalizeMention()', () => {
it('adds base fields', () => { it('adds base fields', () => {
const account = fromJS({}); const account = {};
const result = normalizeMention(account); const result = normalizeMention(account);
expect(ImmutableRecord.isRecord(result)).toBe(true); expect(ImmutableRecord.isRecord(result)).toBe(true);
@ -15,7 +15,7 @@ describe('normalizeMention()', () => {
}); });
it('infers username from acct', () => { it('infers username from acct', () => {
const account = fromJS({ acct: 'alex@gleasonator.com' }); const account = { acct: 'alex@gleasonator.com' };
const result = normalizeMention(account); const result = normalizeMention(account);
expect(result.username).toEqual('alex'); expect(result.username).toEqual('alex');

Wyświetl plik

@ -1,10 +1,10 @@
import { Record as ImmutableRecord, fromJS } from 'immutable'; import { Record as ImmutableRecord } from 'immutable';
import { normalizeNotification } from '../notification'; import { normalizeNotification } from '../notification';
describe('normalizeNotification()', () => { describe('normalizeNotification()', () => {
it('normalizes an empty map', () => { it('normalizes an empty map', () => {
const notification = fromJS({}); const notification = {};
const result = normalizeNotification(notification); const result = normalizeNotification(notification);
expect(ImmutableRecord.isRecord(result)).toBe(true); expect(ImmutableRecord.isRecord(result)).toBe(true);

Wyświetl plik

@ -1,10 +1,10 @@
import { Record as ImmutableRecord, fromJS } from 'immutable'; import { Record as ImmutableRecord } from 'immutable';
import { normalizePoll } from '../poll'; import { normalizePoll } from '../poll';
describe('normalizePoll()', () => { describe('normalizePoll()', () => {
it('adds base fields', () => { it('adds base fields', () => {
const poll = fromJS({ options: [{ title: 'Apples' }] }); const poll = { options: [{ title: 'Apples' }] };
const result = normalizePoll(poll); const result = normalizePoll(poll);
const expected = { const expected = {
@ -25,7 +25,7 @@ describe('normalizePoll()', () => {
}); });
it('normalizes a Pleroma logged-out poll', () => { it('normalizes a Pleroma logged-out poll', () => {
const poll = fromJS(require('soapbox/__fixtures__/pleroma-status-with-poll.json')).get('poll'); const { poll } = require('soapbox/__fixtures__/pleroma-status-with-poll.json');
const result = normalizePoll(poll); const result = normalizePoll(poll);
// Adds logged-in fields // Adds logged-in fields
@ -34,7 +34,7 @@ describe('normalizePoll()', () => {
}); });
it('normalizes poll with emojis', () => { it('normalizes poll with emojis', () => {
const poll = fromJS(require('soapbox/__fixtures__/pleroma-status-with-poll-with-emojis.json')).get('poll'); const { poll } = require('soapbox/__fixtures__/pleroma-status-with-poll-with-emojis.json');
const result = normalizePoll(poll); const result = normalizePoll(poll);
// Emojifies poll options // Emojifies poll options

Wyświetl plik

@ -4,7 +4,7 @@ import { normalizeStatus } from '../status';
describe('normalizeStatus()', () => { describe('normalizeStatus()', () => {
it('adds base fields', () => { it('adds base fields', () => {
const status = fromJS({}); const status = {};
const result = normalizeStatus(status); const result = normalizeStatus(status);
expect(ImmutableRecord.isRecord(result)).toBe(true); expect(ImmutableRecord.isRecord(result)).toBe(true);
@ -17,7 +17,7 @@ describe('normalizeStatus()', () => {
}); });
it('fixes the order of mentions', () => { it('fixes the order of mentions', () => {
const status = fromJS(require('soapbox/__fixtures__/status-unordered-mentions.json')); const status = require('soapbox/__fixtures__/status-unordered-mentions.json');
const expected = ['NEETzsche', 'alex', 'Lumeinshin', 'sneeden']; const expected = ['NEETzsche', 'alex', 'Lumeinshin', 'sneeden'];
@ -30,7 +30,7 @@ describe('normalizeStatus()', () => {
}); });
it('adds mention to self in self-reply on Mastodon', () => { it('adds mention to self in self-reply on Mastodon', () => {
const status = fromJS(require('soapbox/__fixtures__/mastodon-reply-to-self.json')); const status = require('soapbox/__fixtures__/mastodon-reply-to-self.json');
const expected = { const expected = {
id: '106801667066418367', id: '106801667066418367',
@ -48,7 +48,7 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes mentions with only acct', () => { it('normalizes mentions with only acct', () => {
const status = fromJS({ mentions: [{ acct: 'alex@gleasonator.com' }] }); const status = { mentions: [{ acct: 'alex@gleasonator.com' }] };
const expected = [{ const expected = [{
id: '', id: '',
@ -63,7 +63,7 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes Mitra attachments', () => { it('normalizes Mitra attachments', () => {
const status = fromJS(require('soapbox/__fixtures__/mitra-status-with-attachments.json')); const status = require('soapbox/__fixtures__/mitra-status-with-attachments.json');
const expected = [{ const expected = [{
id: '017eeb0e-e5df-30a4-77a7-a929145cb836', id: '017eeb0e-e5df-30a4-77a7-a929145cb836',
@ -97,7 +97,7 @@ describe('normalizeStatus()', () => {
}); });
it('leaves Pleroma attachments alone', () => { it('leaves Pleroma attachments alone', () => {
const status = fromJS(require('soapbox/__fixtures__/pleroma-status-with-attachments.json')); const status = require('soapbox/__fixtures__/pleroma-status-with-attachments.json');
const result = normalizeStatus(status).media_attachments; const result = normalizeStatus(status).media_attachments;
expect(result.size).toBe(4); expect(result.size).toBe(4);
@ -108,15 +108,15 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes Pleroma quote post', () => { it('normalizes Pleroma quote post', () => {
const status = fromJS(require('soapbox/__fixtures__/pleroma-quote-post.json')); const status = require('soapbox/__fixtures__/pleroma-quote-post.json');
const result = normalizeStatus(status); const result = normalizeStatus(status);
expect(result.quote).toEqual(status.getIn(['pleroma', 'quote'])); expect(result.quote).toEqual(fromJS(status.pleroma.quote));
expect(result.pleroma.get('quote')).toBe(undefined); expect(result.pleroma.get('quote')).toBe(undefined);
}); });
it('normalizes GoToSocial status', () => { it('normalizes GoToSocial status', () => {
const status = fromJS(require('soapbox/__fixtures__/gotosocial-status.json')); const status = require('soapbox/__fixtures__/gotosocial-status.json');
const result = normalizeStatus(status); const result = normalizeStatus(status);
// Adds missing fields // Adds missing fields
@ -132,7 +132,7 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes Friendica status', () => { it('normalizes Friendica status', () => {
const status = fromJS(require('soapbox/__fixtures__/friendica-status.json')); const status = require('soapbox/__fixtures__/friendica-status.json');
const result = normalizeStatus(status); const result = normalizeStatus(status);
// Adds missing fields // Adds missing fields
@ -145,7 +145,7 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes poll and poll options', () => { it('normalizes poll and poll options', () => {
const status = fromJS({ poll: { options: [{ title: 'Apples' }] } }); const status = { poll: { options: [{ title: 'Apples' }] } };
const result = normalizeStatus(status); const result = normalizeStatus(status);
const expected = { const expected = {
@ -166,7 +166,7 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes a Pleroma logged-out poll', () => { it('normalizes a Pleroma logged-out poll', () => {
const status = fromJS(require('soapbox/__fixtures__/pleroma-status-with-poll.json')); const status = require('soapbox/__fixtures__/pleroma-status-with-poll.json');
const result = normalizeStatus(status); const result = normalizeStatus(status);
// Adds logged-in fields // Adds logged-in fields
@ -175,7 +175,7 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes poll with emojis', () => { it('normalizes poll with emojis', () => {
const status = fromJS(require('soapbox/__fixtures__/pleroma-status-with-poll-with-emojis.json')); const status = require('soapbox/__fixtures__/pleroma-status-with-poll-with-emojis.json');
const result = normalizeStatus(status); const result = normalizeStatus(status);
// Emojifies poll options // Emojifies poll options
@ -188,7 +188,7 @@ describe('normalizeStatus()', () => {
}); });
it('normalizes a card', () => { it('normalizes a card', () => {
const status = fromJS(require('soapbox/__fixtures__/status-with-card.json')); const status = require('soapbox/__fixtures__/status-with-card.json');
const result = normalizeStatus(status); const result = normalizeStatus(status);
expect(ImmutableRecord.isRecord(result.card)).toBe(true); expect(ImmutableRecord.isRecord(result.card)).toBe(true);

Wyświetl plik

@ -8,16 +8,18 @@ import {
Map as ImmutableMap, Map as ImmutableMap,
List as ImmutableList, List as ImmutableList,
Record as ImmutableRecord, Record as ImmutableRecord,
fromJS,
} from 'immutable'; } from 'immutable';
import emojify from 'soapbox/features/emoji/emoji'; import emojify from 'soapbox/features/emoji/emoji';
import { normalizeEmoji } from 'soapbox/normalizers/emoji'; import { normalizeEmoji } from 'soapbox/normalizers/emoji';
import { IAccount } from 'soapbox/types'; import { IAccount } from 'soapbox/types';
import { acctFull } from 'soapbox/utils/accounts';
import { unescapeHTML } from 'soapbox/utils/html'; import { unescapeHTML } from 'soapbox/utils/html';
import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers'; import { mergeDefined, makeEmojiMap } from 'soapbox/utils/normalizers';
// https://docs.joinmastodon.org/entities/account/ // https://docs.joinmastodon.org/entities/account/
const AccountRecord = ImmutableRecord({ export const AccountRecord = ImmutableRecord({
acct: '', acct: '',
avatar: '', avatar: '',
avatar_static: '', avatar_static: '',
@ -44,6 +46,7 @@ const AccountRecord = ImmutableRecord({
uri: '', uri: '',
url: '', url: '',
username: '', username: '',
website: '',
verified: false, verified: false,
// Internal fields // Internal fields
@ -56,7 +59,7 @@ const AccountRecord = ImmutableRecord({
}); });
// https://docs.joinmastodon.org/entities/field/ // https://docs.joinmastodon.org/entities/field/
const FieldRecord = ImmutableRecord({ export const FieldRecord = ImmutableRecord({
name: '', name: '',
value: '', value: '',
verified_at: null, verified_at: null,
@ -95,6 +98,18 @@ const normalizeAvatar = (account: ImmutableMap<string, any>) => {
}); });
}; };
// Add header, if missing
const normalizeHeader = (account: ImmutableMap<string, any>) => {
const header = account.get('header');
const headerStatic = account.get('header_static');
const missing = require('images/header-missing.png');
return account.withMutations(account => {
account.set('header', header || headerStatic || missing);
account.set('header_static', headerStatic || header || missing);
});
};
// Normalize custom fields // Normalize custom fields
const normalizeFields = (account: ImmutableMap<string, any>) => { const normalizeFields = (account: ImmutableMap<string, any>) => {
return account.update('fields', ImmutableList(), fields => fields.map(FieldRecord)); return account.update('fields', ImmutableList(), fields => fields.map(FieldRecord));
@ -132,11 +147,12 @@ const normalizeVerified = (account: ImmutableMap<string, any>) => {
}); });
}; };
// Normalize Fedibird/Truth Social location // Normalize Fedibird/Truth Social/Pleroma location
const normalizeLocation = (account: ImmutableMap<string, any>) => { const normalizeLocation = (account: ImmutableMap<string, any>) => {
return account.update('location', location => { return account.update('location', location => {
return [ return [
location, location,
account.getIn(['pleroma', 'location']),
account.getIn(['other_settings', 'location']), account.getIn(['other_settings', 'location']),
].find(Boolean); ].find(Boolean);
}); });
@ -180,16 +196,22 @@ const addInternalFields = (account: ImmutableMap<string, any>) => {
}); });
}; };
export const normalizeAccount = (account: ImmutableMap<string, any>): IAccount => { const normalizeFqn = (account: ImmutableMap<string, any>) => {
return account.set('fqn', acctFull(account));
};
export const normalizeAccount = (account: Record<string, any>): IAccount => {
return AccountRecord( return AccountRecord(
account.withMutations(account => { ImmutableMap(fromJS(account)).withMutations(account => {
normalizePleromaLegacyFields(account); normalizePleromaLegacyFields(account);
normalizeEmojis(account); normalizeEmojis(account);
normalizeAvatar(account); normalizeAvatar(account);
normalizeHeader(account);
normalizeFields(account); normalizeFields(account);
normalizeVerified(account); normalizeVerified(account);
normalizeBirthday(account); normalizeBirthday(account);
normalizeLocation(account); normalizeLocation(account);
normalizeFqn(account);
fixUsername(account); fixUsername(account);
fixDisplayName(account); fixDisplayName(account);
addInternalFields(account); addInternalFields(account);

Wyświetl plik

@ -6,12 +6,13 @@
import { import {
Map as ImmutableMap, Map as ImmutableMap,
Record as ImmutableRecord, Record as ImmutableRecord,
fromJS,
} from 'immutable'; } from 'immutable';
import { mergeDefined } from 'soapbox/utils/normalizers'; import { mergeDefined } from 'soapbox/utils/normalizers';
// https://docs.joinmastodon.org/entities/attachment/ // https://docs.joinmastodon.org/entities/attachment/
const AttachmentRecord = ImmutableRecord({ export const AttachmentRecord = ImmutableRecord({
blurhash: undefined, blurhash: undefined,
description: '', description: '',
id: '', id: '',
@ -29,7 +30,7 @@ const AttachmentRecord = ImmutableRecord({
}); });
// Ensure attachments have required fields // Ensure attachments have required fields
export const normalizeAttachment = (attachment: ImmutableMap<string, any>) => { const normalizeUrls = (attachment: ImmutableMap<string, any>) => {
const url = [ const url = [
attachment.get('url'), attachment.get('url'),
attachment.get('preview_url'), attachment.get('preview_url'),
@ -41,5 +42,11 @@ export const normalizeAttachment = (attachment: ImmutableMap<string, any>) => {
preview_url: url, preview_url: url,
}); });
return AttachmentRecord(attachment.mergeWith(mergeDefined, base)); return attachment.mergeWith(mergeDefined, base);
};
export const normalizeAttachment = (attachment: Record<string, any>) => {
return AttachmentRecord(
normalizeUrls(ImmutableMap(fromJS(attachment))),
);
}; };

Wyświetl plik

@ -3,10 +3,10 @@
* Converts API cards into our internal format. * Converts API cards into our internal format.
* @see {@link https://docs.joinmastodon.org/entities/card/} * @see {@link https://docs.joinmastodon.org/entities/card/}
*/ */
import { Record as ImmutableRecord, Map as ImmutableMap } from 'immutable'; import { Record as ImmutableRecord, Map as ImmutableMap, fromJS } from 'immutable';
// https://docs.joinmastodon.org/entities/card/ // https://docs.joinmastodon.org/entities/card/
const CardRecord = ImmutableRecord({ export const CardRecord = ImmutableRecord({
author_name: '', author_name: '',
author_url: '', author_url: '',
blurhash: null, blurhash: null,
@ -23,6 +23,8 @@ const CardRecord = ImmutableRecord({
width: 0, width: 0,
}); });
export const normalizeCard = (card: ImmutableMap<string, any>) => { export const normalizeCard = (card: Record<string, any>) => {
return CardRecord(card); return CardRecord(
ImmutableMap(fromJS(card)),
);
}; };

Wyświetl plik

@ -3,10 +3,10 @@
* Converts API emojis into our internal format. * Converts API emojis into our internal format.
* @see {@link https://docs.joinmastodon.org/entities/emoji/} * @see {@link https://docs.joinmastodon.org/entities/emoji/}
*/ */
import { Record as ImmutableRecord, Map as ImmutableMap } from 'immutable'; import { Record as ImmutableRecord, Map as ImmutableMap, fromJS } from 'immutable';
// https://docs.joinmastodon.org/entities/emoji/ // https://docs.joinmastodon.org/entities/emoji/
const EmojiRecord = ImmutableRecord({ export const EmojiRecord = ImmutableRecord({
category: '', category: '',
shortcode: '', shortcode: '',
static_url: '', static_url: '',
@ -14,6 +14,8 @@ const EmojiRecord = ImmutableRecord({
visible_in_picker: true, visible_in_picker: true,
}); });
export const normalizeEmoji = (emoji: ImmutableMap<string, any>) => { export const normalizeEmoji = (emoji: Record<string, any>) => {
return EmojiRecord(emoji); return EmojiRecord(
ImmutableMap(fromJS(emoji)),
);
}; };

Wyświetl plik

@ -0,0 +1,9 @@
export { AccountRecord, FieldRecord, normalizeAccount } from './account';
export { AttachmentRecord, normalizeAttachment } from './attachment';
export { CardRecord, normalizeCard } from './card';
export { EmojiRecord, normalizeEmoji } from './emoji';
export { InstanceRecord, normalizeInstance } from './instance';
export { MentionRecord, normalizeMention } from './mention';
export { NotificationRecord, normalizeNotification } from './notification';
export { PollRecord, PollOptionRecord, normalizePoll } from './poll';
export { StatusRecord, normalizeStatus } from './status';

Wyświetl plik

@ -7,6 +7,7 @@ import {
Map as ImmutableMap, Map as ImmutableMap,
List as ImmutableList, List as ImmutableList,
Record as ImmutableRecord, Record as ImmutableRecord,
fromJS,
} from 'immutable'; } from 'immutable';
import { parseVersion, PLEROMA } from 'soapbox/utils/features'; import { parseVersion, PLEROMA } from 'soapbox/utils/features';
@ -15,7 +16,7 @@ import { isNumber } from 'soapbox/utils/numbers';
// Use Mastodon defaults // Use Mastodon defaults
// https://docs.joinmastodon.org/entities/instance/ // https://docs.joinmastodon.org/entities/instance/
const InstanceRecord = ImmutableRecord({ export const InstanceRecord = ImmutableRecord({
approval_required: false, approval_required: false,
contact_account: ImmutableMap(), contact_account: ImmutableMap(),
configuration: ImmutableMap({ configuration: ImmutableMap({
@ -83,13 +84,25 @@ const pleromaToMastodonConfig = (instance: ImmutableMap<string, any>) => {
// Get the software's default attachment limit // Get the software's default attachment limit
const getAttachmentLimit = (software: string) => software === PLEROMA ? Infinity : 4; const getAttachmentLimit = (software: string) => software === PLEROMA ? Infinity : 4;
// Normalize instance (Pleroma, Mastodon, etc.) to Mastodon's format // Normalize version
export const normalizeInstance = (instance: ImmutableMap<string, any>) => { const normalizeVersion = (instance: ImmutableMap<string, any>) => {
const { software } = parseVersion(instance.get('version')); return instance.update('version', '0.0.0', version => {
const mastodonConfig = pleromaToMastodonConfig(instance); // Handle Mastodon release candidates
if (new RegExp(/[0-9\.]+rc[0-9]+/g).test(version)) {
return version.split('rc').join('-rc');
} else {
return version;
}
});
};
// Normalize instance (Pleroma, Mastodon, etc.) to Mastodon's format
export const normalizeInstance = (instance: Record<string, any>) => {
return InstanceRecord( return InstanceRecord(
instance.withMutations(instance => { ImmutableMap(fromJS(instance)).withMutations((instance: ImmutableMap<string, any>) => {
const { software } = parseVersion(instance.get('version'));
const mastodonConfig = pleromaToMastodonConfig(instance);
// Merge configuration // Merge configuration
instance.update('configuration', ImmutableMap(), configuration => ( instance.update('configuration', ImmutableMap(), configuration => (
configuration.mergeDeepWith(mergeDefined, mastodonConfig) configuration.mergeDeepWith(mergeDefined, mastodonConfig)
@ -100,6 +113,9 @@ export const normalizeInstance = (instance: ImmutableMap<string, any>) => {
return isNumber(value) ? value : getAttachmentLimit(software); return isNumber(value) ? value : getAttachmentLimit(software);
}); });
// Normalize version
normalizeVersion(instance);
// Merge defaults // Merge defaults
instance.mergeDeepWith(mergeDefined, InstanceRecord()); instance.mergeDeepWith(mergeDefined, InstanceRecord());
}), }),

Wyświetl plik

@ -3,22 +3,19 @@
* Converts API mentions into our internal format. * Converts API mentions into our internal format.
* @see {@link https://docs.joinmastodon.org/entities/mention/} * @see {@link https://docs.joinmastodon.org/entities/mention/}
*/ */
import { import { Record as ImmutableRecord } from 'immutable';
Map as ImmutableMap,
Record as ImmutableRecord,
} from 'immutable';
import { normalizeAccount } from 'soapbox/normalizers/account'; import { normalizeAccount } from 'soapbox/normalizers/account';
// https://docs.joinmastodon.org/entities/mention/ // https://docs.joinmastodon.org/entities/mention/
const MentionRecord = ImmutableRecord({ export const MentionRecord = ImmutableRecord({
id: '', id: '',
acct: '', acct: '',
username: '', username: '',
url: '', url: '',
}); });
export const normalizeMention = (mention: ImmutableMap<string, any>) => { export const normalizeMention = (mention: Record<string, any>) => {
// Simply normalize it as an account then cast it as a mention ¯\_(ツ)_/¯ // Simply normalize it as an account then cast it as a mention ¯\_(ツ)_/¯
return MentionRecord(normalizeAccount(mention)); return MentionRecord(normalizeAccount(mention));
}; };

Wyświetl plik

@ -6,10 +6,11 @@
import { import {
Map as ImmutableMap, Map as ImmutableMap,
Record as ImmutableRecord, Record as ImmutableRecord,
fromJS,
} from 'immutable'; } from 'immutable';
// https://docs.joinmastodon.org/entities/notification/ // https://docs.joinmastodon.org/entities/notification/
const NotificationRecord = ImmutableRecord({ export const NotificationRecord = ImmutableRecord({
account: null, account: null,
chat_message: null, // pleroma:chat_mention chat_message: null, // pleroma:chat_mention
created_at: new Date(), created_at: new Date(),
@ -20,6 +21,8 @@ const NotificationRecord = ImmutableRecord({
type: '', type: '',
}); });
export const normalizeNotification = (notification: ImmutableMap<string, any>) => { export const normalizeNotification = (notification: Record<string, any>) => {
return NotificationRecord(notification); return NotificationRecord(
ImmutableMap(fromJS(notification)),
);
}; };

Wyświetl plik

@ -8,6 +8,7 @@ import {
Map as ImmutableMap, Map as ImmutableMap,
List as ImmutableList, List as ImmutableList,
Record as ImmutableRecord, Record as ImmutableRecord,
fromJS,
} from 'immutable'; } from 'immutable';
import emojify from 'soapbox/features/emoji/emoji'; import emojify from 'soapbox/features/emoji/emoji';
@ -15,7 +16,7 @@ import { normalizeEmoji } from 'soapbox/normalizers/emoji';
import { makeEmojiMap } from 'soapbox/utils/normalizers'; import { makeEmojiMap } from 'soapbox/utils/normalizers';
// https://docs.joinmastodon.org/entities/poll/ // https://docs.joinmastodon.org/entities/poll/
const PollRecord = ImmutableRecord({ export const PollRecord = ImmutableRecord({
emojis: ImmutableList(), emojis: ImmutableList(),
expired: false, expired: false,
expires_at: new Date(), expires_at: new Date(),
@ -29,7 +30,7 @@ const PollRecord = ImmutableRecord({
}); });
// Sub-entity of Poll // Sub-entity of Poll
const PollOptionRecord = ImmutableRecord({ export const PollOptionRecord = ImmutableRecord({
title: '', title: '',
votes_count: 0, votes_count: 0,
@ -76,9 +77,9 @@ const normalizePollVoted = (poll: ImmutableMap<string, any>) => {
}); });
}; };
export const normalizePoll = (poll: ImmutableMap<string, any>) => { export const normalizePoll = (poll: Record<string, any>) => {
return PollRecord( return PollRecord(
poll.withMutations((poll: ImmutableMap<string, any>) => { ImmutableMap(fromJS(poll)).withMutations((poll: ImmutableMap<string, any>) => {
normalizeEmojis(poll); normalizeEmojis(poll);
normalizePollOptions(poll); normalizePollOptions(poll);
normalizePollOwnVotes(poll); normalizePollOwnVotes(poll);

Wyświetl plik

@ -7,6 +7,7 @@ import {
Map as ImmutableMap, Map as ImmutableMap,
List as ImmutableList, List as ImmutableList,
Record as ImmutableRecord, Record as ImmutableRecord,
fromJS,
} from 'immutable'; } from 'immutable';
import { normalizeAttachment } from 'soapbox/normalizers/attachment'; import { normalizeAttachment } from 'soapbox/normalizers/attachment';
@ -17,7 +18,7 @@ import { normalizePoll } from 'soapbox/normalizers/poll';
import { IStatus } from 'soapbox/types'; import { IStatus } from 'soapbox/types';
// https://docs.joinmastodon.org/entities/status/ // https://docs.joinmastodon.org/entities/status/
const StatusRecord = ImmutableRecord({ export const StatusRecord = ImmutableRecord({
account: null, account: null,
application: null, application: null,
bookmarked: false, bookmarked: false,
@ -135,9 +136,9 @@ const fixQuote = (status: ImmutableMap<string, any>) => {
}); });
}; };
export const normalizeStatus = (status: ImmutableMap<string, any>): IStatus => { export const normalizeStatus = (status: Record<string, any>): IStatus => {
return StatusRecord( return StatusRecord(
status.withMutations(status => { ImmutableMap(fromJS(status)).withMutations(status => {
normalizeAttachments(status); normalizeAttachments(status);
normalizeMentions(status); normalizeMentions(status);
normalizeEmojis(status); normalizeEmojis(status);

Wyświetl plik

@ -1,10 +1,11 @@
import { Map as ImmutableMap } from 'immutable'; import { Map as ImmutableMap, fromJS } from 'immutable';
import * as actions from 'soapbox/actions/compose'; import * as actions from 'soapbox/actions/compose';
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS } from 'soapbox/actions/me'; import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS } from 'soapbox/actions/me';
import { SETTING_CHANGE } from 'soapbox/actions/settings'; import { SETTING_CHANGE } from 'soapbox/actions/settings';
//import { REDRAFT } from 'soapbox/actions/statuses'; import { REDRAFT } from 'soapbox/actions/statuses';
import { TIMELINE_DELETE } from 'soapbox/actions/timelines'; import { TIMELINE_DELETE } from 'soapbox/actions/timelines';
import { normalizeStatus } from 'soapbox/normalizers/status';
import reducer from '../compose'; import reducer from '../compose';
@ -38,6 +39,29 @@ describe('compose reducer', () => {
expect(state.get('idempotencyKey').length === 36); expect(state.get('idempotencyKey').length === 36);
}); });
describe('REDRAFT', () => {
it('strips Pleroma integer attachments', () => {
const action = {
type: REDRAFT,
status: normalizeStatus(fromJS(require('soapbox/__fixtures__/pleroma-status-deleted.json'))),
v: { software: 'Pleroma' },
};
const result = reducer(undefined, action);
expect(result.get('media_attachments').isEmpty()).toBe(true);
});
it('leaves non-Pleroma integer attachments alone', () => {
const action = {
type: REDRAFT,
status: normalizeStatus(fromJS(require('soapbox/__fixtures__/pleroma-status-deleted.json'))),
};
const result = reducer(undefined, action);
expect(result.getIn(['media_attachments', 0, 'id'])).toEqual('508107650');
});
});
it('uses \'public\' scope as default', () => { it('uses \'public\' scope as default', () => {
const action = { const action = {
type: actions.COMPOSE_REPLY, type: actions.COMPOSE_REPLY,
@ -325,30 +349,6 @@ describe('compose reducer', () => {
}); });
}); });
// it('should handle COMPOSE_UPLOAD_UNDO', () => {
// const state = ImmutableMap({
// media_attachments: ImmutableList([
// description: null,
// id: '1375732379',
// pleroma: {
// mime_type: 'image/jpeg'
// },
// preview_url: 'https://media.gleasonator.com/media_attachments/files/000/853/856/original/7035d67937053e1d.jpg',
// remote_url: 'https://media.gleasonator.com/media_attachments/files/000/853/856/original/7035d67937053e1d.jpg',
// text_url: 'https://media.gleasonator.com/media_attachments/files/000/853/856/original/7035d67937053e1d.jpg',
// type: 'image',
// url: 'https://media.gleasonator.com/media_attachments/files/000/853/856/original/7035d67937053e1d.jpg'
// ]),
// });
// const action = {
// type: actions.COMPOSE_UPLOAD_UNDO,
// mediaId: '1375732379',
// };
// expect(reducer(state, action)).toEqual({
// media_attachments: [],
// });
// });
it('should handle COMPOSE_UPLOAD_PROGRESS', () => { it('should handle COMPOSE_UPLOAD_PROGRESS', () => {
const state = ImmutableMap({ progress: 0 }); const state = ImmutableMap({ progress: 0 });
const action = { const action = {
@ -361,203 +361,6 @@ describe('compose reducer', () => {
}); });
}); });
// it('should handle COMPOSE_MENTION', () => {
// const state = ImmutableMap({});
// const account = {
// '9w1HhmenIAKBHJiUs4': {
// header_static: 'https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png',
// display_name_html: 'Alex Gleason',
// bot: false,
// display_name: 'Alex Gleason',
// created_at: '2020-06-12T21:47:28.000Z',
// locked: false,
// emojis: [],
// header: 'https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png',
// url: 'https://gleasonator.com/users/alex',
// note: 'Fediverse developer. I come in peace. <a class="hashtag" data-tag="vegan" href="https://gleasonator.com/tag/vegan">#vegan</a> <a class="hashtag" data-tag="freeculture" href="https://gleasonator.com/tag/freeculture">#freeculture</a> <a class="hashtag" data-tag="atheist" href="https://gleasonator.com/tag/atheist">#atheist</a> <a class="hashtag" data-tag="antiporn" href="https://gleasonator.com/tag/antiporn">#antiporn</a> <a class="hashtag" data-tag="gendercritical" href="https://gleasonator.com/tag/gendercritical">#gendercritical</a>. Boosts ≠ endorsements.',
// acct: 'alex@gleasonator.com',
// avatar_static: 'https://media.gleasonator.com/accounts/avatars/000/000/001/original/1a630e4c4c64c948.jpg',
// username: 'alex',
// avatar: 'https://media.gleasonator.com/accounts/avatars/000/000/001/original/1a630e4c4c64c948.jpg',
// fields: [
// {
// name: 'Website',
// value: '<a href="https://alexgleason.me" rel="ugc">https://alexgleason.me</a>',
// name_emojified: 'Website',
// value_emojified: '<a href="https://alexgleason.me" rel="ugc">https://alexgleason.me</a>',
// value_plain: 'https://alexgleason.me'
// },
// {
// name: 'Pleroma+Soapbox',
// value: '<a href="https://soapbox.pub" rel="ugc">https://soapbox.pub</a>',
// name_emojified: 'Pleroma+Soapbox',
// value_emojified: '<a href="https://soapbox.pub" rel="ugc">https://soapbox.pub</a>',
// value_plain: 'https://soapbox.pub'
// },
// {
// name: 'Email',
// value: 'alex@alexgleason.me',
// name_emojified: 'Email',
// value_emojified: 'alex@alexgleason.me',
// value_plain: 'alex@alexgleason.me'
// },
// {
// name: 'Gender identity',
// value: 'Soyboy',
// name_emojified: 'Gender identity',
// value_emojified: 'Soyboy',
// value_plain: 'Soyboy'
// }
// ],
// pleroma: {
// hide_follows: false,
// hide_followers_count: false,
// background_image: null,
// confirmation_pending: false,
// is_moderator: false,
// hide_follows_count: false,
// hide_followers: false,
// relationship: {
// showing_reblogs: true,
// followed_by: false,
// subscribing: false,
// blocked_by: false,
// requested: false,
// domain_blocking: false,
// following: false,
// endorsed: false,
// blocking: false,
// muting: false,
// id: '9w1HhmenIAKBHJiUs4',
// muting_notifications: false
// },
// tags: [],
// hide_favorites: true,
// is_admin: false,
// skip_thread_containment: false
// },
// source: {
// fields: [],
// note: 'Fediverse developer. I come in peace. #vegan #freeculture #atheist #antiporn #gendercritical. Boosts ≠ endorsements.',
// pleroma: {
// actor_type: 'Person',
// discoverable: false
// },
// sensitive: false
// },
// id: '9w1HhmenIAKBHJiUs4',
// note_emojified: 'Fediverse developer. I come in peace. <a class="hashtag" data-tag="vegan" href="https://gleasonator.com/tag/vegan">#vegan</a> <a class="hashtag" data-tag="freeculture" href="https://gleasonator.com/tag/freeculture">#freeculture</a> <a class="hashtag" data-tag="atheist" href="https://gleasonator.com/tag/atheist">#atheist</a> <a class="hashtag" data-tag="antiporn" href="https://gleasonator.com/tag/antiporn">#antiporn</a> <a class="hashtag" data-tag="gendercritical" href="https://gleasonator.com/tag/gendercritical">#gendercritical</a>. Boosts ≠ endorsements.'
// },
// };
// const action = {
// type: actions.COMPOSE_MENTION,
// account: account,
// };
// expect(reducer(state, action).toJS()).toMatchObject({
// text: '@alex@gleasonator.com',
// caretPosition: null,
// });
// });
// it('should handle COMPOSE_DIRECT', () => {
// const state = ImmutableMap({});
// const account = {
// '9w1HhmenIAKBHJiUs4': {
// header_static: 'https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png',
// display_name_html: 'Alex Gleason',
// bot: false,
// display_name: 'Alex Gleason',
// created_at: '2020-06-12T21:47:28.000Z',
// locked: false,
// emojis: [],
// header: 'https://media.gleasonator.com/accounts/headers/000/000/001/original/9d0e4dbf1c9dbc8f.png',
// url: 'https://gleasonator.com/users/alex',
// note: 'Fediverse developer. I come in peace. <a class="hashtag" data-tag="vegan" href="https://gleasonator.com/tag/vegan">#vegan</a> <a class="hashtag" data-tag="freeculture" href="https://gleasonator.com/tag/freeculture">#freeculture</a> <a class="hashtag" data-tag="atheist" href="https://gleasonator.com/tag/atheist">#atheist</a> <a class="hashtag" data-tag="antiporn" href="https://gleasonator.com/tag/antiporn">#antiporn</a> <a class="hashtag" data-tag="gendercritical" href="https://gleasonator.com/tag/gendercritical">#gendercritical</a>. Boosts ≠ endorsements.',
// acct: 'alex@gleasonator.com',
// avatar_static: 'https://media.gleasonator.com/accounts/avatars/000/000/001/original/1a630e4c4c64c948.jpg',
// username: 'alex',
// avatar: 'https://media.gleasonator.com/accounts/avatars/000/000/001/original/1a630e4c4c64c948.jpg',
// fields: [
// {
// name: 'Website',
// value: '<a href="https://alexgleason.me" rel="ugc">https://alexgleason.me</a>',
// name_emojified: 'Website',
// value_emojified: '<a href="https://alexgleason.me" rel="ugc">https://alexgleason.me</a>',
// value_plain: 'https://alexgleason.me'
// },
// {
// name: 'Pleroma+Soapbox',
// value: '<a href="https://soapbox.pub" rel="ugc">https://soapbox.pub</a>',
// name_emojified: 'Pleroma+Soapbox',
// value_emojified: '<a href="https://soapbox.pub" rel="ugc">https://soapbox.pub</a>',
// value_plain: 'https://soapbox.pub'
// },
// {
// name: 'Email',
// value: 'alex@alexgleason.me',
// name_emojified: 'Email',
// value_emojified: 'alex@alexgleason.me',
// value_plain: 'alex@alexgleason.me'
// },
// {
// name: 'Gender identity',
// value: 'Soyboy',
// name_emojified: 'Gender identity',
// value_emojified: 'Soyboy',
// value_plain: 'Soyboy'
// }
// ],
// pleroma: {
// hide_follows: false,
// hide_followers_count: false,
// background_image: null,
// confirmation_pending: false,
// is_moderator: false,
// hide_follows_count: false,
// hide_followers: false,
// relationship: {
// showing_reblogs: true,
// followed_by: false,
// subscribing: false,
// blocked_by: false,
// requested: false,
// domain_blocking: false,
// following: false,
// endorsed: false,
// blocking: false,
// muting: false,
// id: '9w1HhmenIAKBHJiUs4',
// muting_notifications: false
// },
// tags: [],
// hide_favorites: true,
// is_admin: false,
// skip_thread_containment: false
// },
// source: {
// fields: [],
// note: 'Fediverse developer. I come in peace. #vegan #freeculture #atheist #antiporn #gendercritical. Boosts ≠ endorsements.',
// pleroma: {
// actor_type: 'Person',
// discoverable: false
// },
// sensitive: false
// },
// id: '9w1HhmenIAKBHJiUs4',
// note_emojified: 'Fediverse developer. I come in peace. <a class="hashtag" data-tag="vegan" href="https://gleasonator.com/tag/vegan">#vegan</a> <a class="hashtag" data-tag="freeculture" href="https://gleasonator.com/tag/freeculture">#freeculture</a> <a class="hashtag" data-tag="atheist" href="https://gleasonator.com/tag/atheist">#atheist</a> <a class="hashtag" data-tag="antiporn" href="https://gleasonator.com/tag/antiporn">#antiporn</a> <a class="hashtag" data-tag="gendercritical" href="https://gleasonator.com/tag/gendercritical">#gendercritical</a>. Boosts ≠ endorsements.'
// }
// };
// const action = {
// type: actions.COMPOSE_DIRECT,
// account: account,
// };
// expect(reducer(state, action).toJS()).toMatchObject({
// text: '@alex@gleasonator.com',
// caretPosition: null,
// privacy: 'direct',
// });
// });
//
it('should handle COMPOSE_SUGGESTIONS_CLEAR', () => { it('should handle COMPOSE_SUGGESTIONS_CLEAR', () => {
const state = ImmutableMap({ }); const state = ImmutableMap({ });
const action = { const action = {
@ -570,28 +373,6 @@ describe('compose reducer', () => {
}); });
}); });
// it('should handle COMPOSE_SUGGESTIONS_READY', () => {
// const state = ImmutableMap({ default_privacy: 'public', privacy: 'public'});
// const action = {
// type: actions.COMPOSE_SUGGESTIONS_READY,
// };
// expect(reducer(state, action).toJS()).toMatchObject({
// default_privacy: 'unlisted',
// privacy: 'public',
// });
// });
//
// it('should handle COMPOSE_SUGGESTION_SELECT', () => {
// const state = ImmutableMap({ default_privacy: 'public', privacy: 'public'});
// const action = {
// type: actions.COMPOSE_SUGGESTION_SELECT,
// };
// expect(reducer(state, action).toJS()).toMatchObject({
// default_privacy: 'unlisted',
// privacy: 'public',
// });
// });
//
it('should handle COMPOSE_SUGGESTION_TAGS_UPDATE', () => { it('should handle COMPOSE_SUGGESTION_TAGS_UPDATE', () => {
const state = ImmutableMap({ tagHistory: [ 'hashtag' ] }); const state = ImmutableMap({ tagHistory: [ 'hashtag' ] });
const action = { const action = {
@ -627,42 +408,6 @@ describe('compose reducer', () => {
}); });
}); });
// it('should handle COMPOSE_EMOJI_INSERT', () => {
// const state = ImmutableMap({ text: 'this is my' });
// const action = {
// type: actions.COMPOSE_EMOJI_INSERT,
// position: 11,
// emoji: [],
// needsSpace, true,
// };
// expect(reducer(state, action).toJS()).toMatchObject({
// text: 'this is my :emoji:',
// caretPosition: 15,
// });
// });
//
// it('should handle COMPOSE_UPLOAD_CHANGE_SUCCESS', () => {
// const state = ImmutableMap({ default_privacy: 'public' });
// const action = {
// type: actions.COMPOSE_UPLOAD_CHANGE_SUCCESS,
// };
// expect(reducer(state, action).toJS()).toMatchObject({
// default_privacy: 'unlisted',
// privacy: 'public',
// });
// });
//
// it('should handle REDRAFT', () => {
// const state = ImmutableMap({ default_privacy: 'public' });
// const action = {
// type: REDRAFT,
// };
// expect(reducer(state, action).toJS()).toMatchObject({
// default_privacy: 'unlisted',
// privacy: 'public',
// });
// });
//
it('should handle COMPOSE_POLL_ADD', () => { it('should handle COMPOSE_POLL_ADD', () => {
const state = ImmutableMap({ poll: null }); const state = ImmutableMap({ poll: null });
const initialPoll = Object({ const initialPoll = Object({
@ -691,34 +436,6 @@ describe('compose reducer', () => {
}); });
}); });
// it('should handle COMPOSE_POLL_OPTION_ADD', () => {
// const initialPoll = Object({
// options: [
// 'option 1',
// 'option 2',
// ],
// expires_in: 86400,
// multiple: false
// });
// const state = ImmutableMap({ poll: initialPoll });
// const action = {
// type: actions.COMPOSE_POLL_OPTION_ADD,
// title: 'option 3',
// };
// const updatedPoll = Object({
// options: [
// 'option 1',
// 'option 2',
// 'option 3',
// ],
// expires_in: 86400,
// multiple: false,
// });
// expect(reducer(state, action).toJS()).toMatchObject({
// poll: updatedPoll,
// });
// });
it('should handle COMPOSE_POLL_OPTION_CHANGE', () => { it('should handle COMPOSE_POLL_OPTION_CHANGE', () => {
const initialPoll = Object({ const initialPoll = Object({
options: [ options: [
@ -747,32 +464,6 @@ describe('compose reducer', () => {
}); });
}); });
// it('should handle COMPOSE_POLL_OPTION_REMOVE', () => {
// const initialPoll = Object({
// options: [
// 'option 1',
// 'option 2',
// ],
// expires_in: 86400,
// multiple: false,
// });
// const state = ImmutableMap({ poll: initialPoll });
// const action = {
// type: actions.COMPOSE_POLL_OPTION_REMOVE,
// index: 1,
// };
// const updatedPoll = Object({
// options: [
// 'option 1',
// ],
// expires_in: 86400,
// multiple: false,
// });
// expect(reducer(state, action).toJS()).toMatchObject({
// poll: updatedPoll,
// });
// });
it('sets the post content-type', () => { it('sets the post content-type', () => {
const action = { const action = {
type: actions.COMPOSE_TYPE_CHANGE, type: actions.COMPOSE_TYPE_CHANGE,

Wyświetl plik

@ -93,6 +93,22 @@ describe('notifications reducer', () => {
expect(result.items.size).toEqual(1); expect(result.items.size).toEqual(1);
expect(result.items.get('4').id).toEqual('4'); expect(result.items.get('4').id).toEqual('4');
}); });
it('imports move notification', () => {
const action = {
type: NOTIFICATIONS_EXPAND_SUCCESS,
notifications: [
require('soapbox/__fixtures__/pleroma-notification-move.json'),
],
next: null,
skipLoading: true,
};
const result = reducer(undefined, action).items.get('406814');
expect(result.account).toEqual('AFmHQ18XZ7Lco68MW8');
expect(result.target).toEqual('A5c5LK7EJTFR0u26Pg');
});
}); });
describe('NOTIFICATIONS_EXPAND_REQUEST', () => { describe('NOTIFICATIONS_EXPAND_REQUEST', () => {

Wyświetl plik

@ -46,7 +46,7 @@ const minifyAccount = account => {
}; };
const fixAccount = (state, account) => { const fixAccount = (state, account) => {
const normalized = minifyAccount(normalizeAccount(fromJS(account))); const normalized = minifyAccount(normalizeAccount(account));
return state.set(account.id, normalized); return state.set(account.id, normalized);
}; };
@ -119,7 +119,7 @@ const removePermission = (state, accountIds, permissionGroup) => {
}); });
}; };
const buildAccount = adminUser => normalizeAccount(fromJS({ const buildAccount = adminUser => normalizeAccount({
id: adminUser.get('id'), id: adminUser.get('id'),
username: adminUser.get('nickname').split('@')[0], username: adminUser.get('nickname').split('@')[0],
acct: adminUser.get('nickname'), acct: adminUser.get('nickname'),
@ -142,7 +142,7 @@ const buildAccount = adminUser => normalizeAccount(fromJS({
}, },
}, },
should_refetch: true, should_refetch: true,
})); });
const mergeAdminUser = (account, adminUser) => { const mergeAdminUser = (account, adminUser) => {
return account.withMutations(account => { return account.withMutations(account => {

Wyświetl plik

@ -1,6 +1,8 @@
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable'; import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
import { tagHistory } from 'soapbox/settings'; import { tagHistory } from 'soapbox/settings';
import { PLEROMA } from 'soapbox/utils/features';
import { hasIntegerMediaIds } from 'soapbox/utils/status';
import { import {
COMPOSE_MOUNT, COMPOSE_MOUNT,
@ -431,13 +433,17 @@ export default function compose(state = initialState, action) {
map.set('to', action.explicitAddressing ? getExplicitMentions(action.status.get('account', 'id'), action.status) : undefined); map.set('to', action.explicitAddressing ? getExplicitMentions(action.status.get('account', 'id'), action.status) : undefined);
map.set('in_reply_to', action.status.get('in_reply_to_id')); map.set('in_reply_to', action.status.get('in_reply_to_id'));
map.set('privacy', action.status.get('visibility')); map.set('privacy', action.status.get('visibility'));
// TODO: Actually fix this rather than just removing it
// map.set('media_attachments', action.status.get('media_attachments'));
map.set('focusDate', new Date()); map.set('focusDate', new Date());
map.set('caretPosition', null); map.set('caretPosition', null);
map.set('idempotencyKey', uuid()); map.set('idempotencyKey', uuid());
map.set('content_type', action.content_type || 'text/plain'); map.set('content_type', action.content_type || 'text/plain');
if (action.v?.software === PLEROMA && hasIntegerMediaIds(action.status)) {
map.set('media_attachments', ImmutableList());
} else {
map.set('media_attachments', action.status.get('media_attachments'));
}
if (action.status.get('spoiler_text').length > 0) { if (action.status.get('spoiler_text').length > 0) {
map.set('spoiler', true); map.set('spoiler', true);
map.set('spoiler_text', action.status.get('spoiler_text')); map.set('spoiler_text', action.status.get('spoiler_text'));

Wyświetl plik

@ -116,7 +116,7 @@ const reducers = {
}; };
// Build a default state from all reducers: it has the key and `undefined` // Build a default state from all reducers: it has the key and `undefined`
const StateRecord = ImmutableRecord( export const StateRecord = ImmutableRecord(
Object.keys(reducers).reduce((params: Record<string, any>, reducer) => { Object.keys(reducers).reduce((params: Record<string, any>, reducer) => {
params[reducer] = undefined; params[reducer] = undefined;
return params; return params;

Wyświetl plik

@ -56,6 +56,7 @@ const comparator = (a, b) => {
const minifyNotification = notification => { const minifyNotification = notification => {
return notification.mergeWith((o, n) => n || o, { return notification.mergeWith((o, n) => n || o, {
account: notification.getIn(['account', 'id']), account: notification.getIn(['account', 'id']),
target: notification.getIn(['target', 'id']),
status: notification.getIn(['status', 'id']), status: notification.getIn(['status', 'id']),
}); });
}; };

Wyświetl plik

@ -1,4 +1,4 @@
import { Map as ImmutableMap, fromJS } from 'immutable'; import { Map as ImmutableMap } from 'immutable';
import { POLLS_IMPORT } from 'soapbox/actions/importer'; import { POLLS_IMPORT } from 'soapbox/actions/importer';
import { normalizeStatus } from 'soapbox/normalizers/status'; import { normalizeStatus } from 'soapbox/normalizers/status';
@ -6,7 +6,7 @@ import { normalizeStatus } from 'soapbox/normalizers/status';
// HOTFIX: Convert the poll into a fake status to normalize it... // HOTFIX: Convert the poll into a fake status to normalize it...
// TODO: get rid of POLLS_IMPORT and use STATUS_IMPORT here. // TODO: get rid of POLLS_IMPORT and use STATUS_IMPORT here.
const normalizePoll = poll => { const normalizePoll = poll => {
const status = fromJS({ poll }); const status = { poll };
return normalizeStatus(status).poll; return normalizeStatus(status).poll;
}; };

Wyświetl plik

@ -11,6 +11,9 @@ import thunk from 'redux-thunk';
import rootReducer from 'soapbox/reducers'; import rootReducer from 'soapbox/reducers';
export const rootState = rootReducer(undefined, {});
export const getState = () => rootState;
// Mock Redux // Mock Redux
// https://redux.js.org/recipes/writing-tests/ // https://redux.js.org/recipes/writing-tests/
const middlewares = [thunk]; const middlewares = [thunk];
@ -20,7 +23,7 @@ export const mockStore = configureMockStore(middlewares);
export const createComponent = (children, props = {}) => { export const createComponent = (children, props = {}) => {
props = ImmutableMap({ props = ImmutableMap({
locale: 'en', locale: 'en',
store: mockStore(rootReducer(ImmutableMap(), {})), store: mockStore(rootState),
}).merge(props); }).merge(props);
return renderer.create( return renderer.create(

Wyświetl plik

@ -0,0 +1,13 @@
import { isIntegerId } from '../numbers';
test('isIntegerId()', () => {
expect(isIntegerId('0')).toBe(true);
expect(isIntegerId('1')).toBe(true);
expect(isIntegerId('508107650')).toBe(true);
expect(isIntegerId('-1764036199')).toBe(true);
expect(isIntegerId('106801667066418367')).toBe(true);
expect(isIntegerId('9v5bmRalQvjOy0ECcC')).toBe(false);
expect(isIntegerId(null)).toBe(false);
expect(isIntegerId(undefined)).toBe(false);
expect(isIntegerId()).toBe(false);
});

Wyświetl plik

@ -0,0 +1,12 @@
import { fromJS } from 'immutable';
import { normalizeStatus } from 'soapbox/normalizers/status';
import { hasIntegerMediaIds } from '../status';
describe('hasIntegerMediaIds()', () => {
it('returns true for a Pleroma deleted status', () => {
const status = normalizeStatus(fromJS(require('soapbox/__fixtures__/pleroma-status-deleted.json')));
expect(hasIntegerMediaIds(status)).toBe(true);
});
});

Wyświetl plik

@ -10,14 +10,14 @@ const getDomainFromURL = (account: ImmutableMap<string, any>): string => {
}; };
export const getDomain = (account: ImmutableMap<string, any>): string => { export const getDomain = (account: ImmutableMap<string, any>): string => {
const domain = account.get('acct').split('@')[1]; const domain = account.get('acct', '').split('@')[1];
return domain ? domain : getDomainFromURL(account); return domain ? domain : getDomainFromURL(account);
}; };
export const guessFqn = (account: ImmutableMap<string, any>): string => { export const guessFqn = (account: ImmutableMap<string, any>): string => {
const [user, domain] = account.get('acct').split('@'); const [user, domain] = account.get('acct', '').split('@');
if (!domain) return [user, getDomainFromURL(account)].join('@'); if (!domain) return [user, getDomainFromURL(account)].join('@');
return account.get('acct'); return account.get('acct', '');
}; };
export const getBaseURL = (account: ImmutableMap<string, any>): string => { export const getBaseURL = (account: ImmutableMap<string, any>): string => {
@ -31,7 +31,7 @@ export const getBaseURL = (account: ImmutableMap<string, any>): string => {
// user@domain even for local users // user@domain even for local users
export const acctFull = (account: ImmutableMap<string, any>): string => ( export const acctFull = (account: ImmutableMap<string, any>): string => (
account.get('fqn') || guessFqn(account) account.get('fqn') || guessFqn(account) || ''
); );
export const getAcct = (account: ImmutableMap<string, any>, displayFqn: boolean): string => ( export const getAcct = (account: ImmutableMap<string, any>, displayFqn: boolean): string => (

Wyświetl plik

@ -12,3 +12,5 @@ export const shortNumberFormat = number => {
return <span><FormattedNumber value={number / 1000} maximumFractionDigits={1} />K</span>; return <span><FormattedNumber value={number / 1000} maximumFractionDigits={1} />K</span>;
} }
}; };
export const isIntegerId = id => new RegExp(/^-?[0-9]+$/g).test(id);

Wyświetl plik

@ -1,3 +1,5 @@
import { isIntegerId } from 'soapbox/utils/numbers';
export const getFirstExternalLink = status => { export const getFirstExternalLink = status => {
try { try {
// Pulled from Pleroma's media parser // Pulled from Pleroma's media parser
@ -13,3 +15,8 @@ export const getFirstExternalLink = status => {
export const shouldHaveCard = status => { export const shouldHaveCard = status => {
return Boolean(getFirstExternalLink(status)); return Boolean(getFirstExternalLink(status));
}; };
// https://gitlab.com/soapbox-pub/soapbox-fe/-/merge_requests/1087
export const hasIntegerMediaIds = status => {
return status.media_attachments.some(({ id }) => isIntegerId(id));
};

Wyświetl plik

@ -487,6 +487,7 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
max-height: 19px;
a { a {
color: var(--highlight-text-color); color: var(--highlight-text-color);

Wyświetl plik

@ -158,7 +158,6 @@
"substring-trie": "^1.0.2", "substring-trie": "^1.0.2",
"terser-webpack-plugin": "^5.2.3", "terser-webpack-plugin": "^5.2.3",
"tiny-queue": "^0.2.1", "tiny-queue": "^0.2.1",
"ts-jest": "^27.0.5",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"tslib": "^2.3.1", "tslib": "^2.3.1",
"twemoji": "https://github.com/twitter/twemoji#v13.0.2", "twemoji": "https://github.com/twitter/twemoji#v13.0.2",
@ -173,6 +172,9 @@
"wicg-inert": "^3.1.1" "wicg-inert": "^3.1.1"
}, },
"devDependencies": { "devDependencies": {
"@jest/globals": "^27.5.1",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"axios-mock-adapter": "^1.18.1", "axios-mock-adapter": "^1.18.1",
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",
"babel-jest": "^27.1.0", "babel-jest": "^27.1.0",
@ -194,6 +196,7 @@
"stylelint": "^13.7.2", "stylelint": "^13.7.2",
"stylelint-config-standard": "^22.0.0", "stylelint-config-standard": "^22.0.0",
"stylelint-scss": "^3.18.0", "stylelint-scss": "^3.18.0",
"ts-jest": "^27.0.5",
"webpack-dev-server": "^4.1.0", "webpack-dev-server": "^4.1.0",
"yargs": "^16.0.3" "yargs": "^16.0.3"
} }

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 116 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 160 KiB

Wyświetl plik

@ -12,5 +12,5 @@
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"typeRoots": [ "./types", "./node_modules/@types"] "typeRoots": [ "./types", "./node_modules/@types"]
}, },
"exclude": ["node_modules", "types"] "exclude": ["node_modules", "types", "**/*.test.*", "**/__mocks__/*", "**/__tests__/*"]
} }

296
yarn.lock
Wyświetl plik

@ -1453,6 +1453,16 @@
"@types/node" "*" "@types/node" "*"
jest-mock "^27.1.1" jest-mock "^27.1.1"
"@jest/environment@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74"
integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==
dependencies:
"@jest/fake-timers" "^27.5.1"
"@jest/types" "^27.5.1"
"@types/node" "*"
jest-mock "^27.5.1"
"@jest/fake-timers@^27.2.0": "@jest/fake-timers@^27.2.0":
version "27.2.0" version "27.2.0"
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.2.0.tgz#560841bc21ae7fbeff0cbff8de8f5cf43ad3561d" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.2.0.tgz#560841bc21ae7fbeff0cbff8de8f5cf43ad3561d"
@ -1465,6 +1475,18 @@
jest-mock "^27.1.1" jest-mock "^27.1.1"
jest-util "^27.2.0" jest-util "^27.2.0"
"@jest/fake-timers@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74"
integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==
dependencies:
"@jest/types" "^27.5.1"
"@sinonjs/fake-timers" "^8.0.1"
"@types/node" "*"
jest-message-util "^27.5.1"
jest-mock "^27.5.1"
jest-util "^27.5.1"
"@jest/globals@^27.2.0": "@jest/globals@^27.2.0":
version "27.2.0" version "27.2.0"
resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.2.0.tgz#4d7085f51df5ac70c8240eb3501289676503933d" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.2.0.tgz#4d7085f51df5ac70c8240eb3501289676503933d"
@ -1474,6 +1496,15 @@
"@jest/types" "^27.1.1" "@jest/types" "^27.1.1"
expect "^27.2.0" expect "^27.2.0"
"@jest/globals@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b"
integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==
dependencies:
"@jest/environment" "^27.5.1"
"@jest/types" "^27.5.1"
expect "^27.5.1"
"@jest/reporters@^27.2.0": "@jest/reporters@^27.2.0":
version "27.2.0" version "27.2.0"
resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.2.0.tgz#629886d9a42218e504a424889a293abb27919e25" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.2.0.tgz#629886d9a42218e504a424889a293abb27919e25"
@ -1565,6 +1596,17 @@
"@types/yargs" "^16.0.0" "@types/yargs" "^16.0.0"
chalk "^4.0.0" chalk "^4.0.0"
"@jest/types@^27.5.1":
version "27.5.1"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80"
integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^3.0.0"
"@types/node" "*"
"@types/yargs" "^16.0.0"
chalk "^4.0.0"
"@lcdp/offline-plugin@^5.1.0": "@lcdp/offline-plugin@^5.1.0":
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/@lcdp/offline-plugin/-/offline-plugin-5.1.0.tgz#826f3e10d618711bd002afd674edb36dc1d9a792" resolved "https://registry.yarnpkg.com/@lcdp/offline-plugin/-/offline-plugin-5.1.0.tgz#826f3e10d618711bd002afd674edb36dc1d9a792"
@ -1703,6 +1745,13 @@
dependencies: dependencies:
"@sinonjs/commons" "^1.7.0" "@sinonjs/commons" "^1.7.0"
"@sinonjs/fake-timers@^8.0.1":
version "8.1.0"
resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7"
integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==
dependencies:
"@sinonjs/commons" "^1.7.0"
"@stylelint/postcss-css-in-js@^0.37.2": "@stylelint/postcss-css-in-js@^0.37.2":
version "0.37.2" version "0.37.2"
resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2" resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2"
@ -1852,6 +1901,11 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
"@types/json-schema@^7.0.9":
version "7.0.10"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23"
integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A==
"@types/json5@^0.0.29": "@types/json5@^0.0.29":
version "0.0.29" version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@ -1962,6 +2016,86 @@
dependencies: dependencies:
"@types/yargs-parser" "*" "@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz#c28ef7f2e688066db0b6a9d95fb74185c114fb9a"
integrity sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==
dependencies:
"@typescript-eslint/scope-manager" "5.15.0"
"@typescript-eslint/type-utils" "5.15.0"
"@typescript-eslint/utils" "5.15.0"
debug "^4.3.2"
functional-red-black-tree "^1.0.1"
ignore "^5.1.8"
regexpp "^3.2.0"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/parser@^5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.15.0.tgz#95f603f8fe6eca7952a99bfeef9b85992972e728"
integrity sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==
dependencies:
"@typescript-eslint/scope-manager" "5.15.0"
"@typescript-eslint/types" "5.15.0"
"@typescript-eslint/typescript-estree" "5.15.0"
debug "^4.3.2"
"@typescript-eslint/scope-manager@5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz#d97afab5e0abf4018d1289bd711be21676cdd0ee"
integrity sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==
dependencies:
"@typescript-eslint/types" "5.15.0"
"@typescript-eslint/visitor-keys" "5.15.0"
"@typescript-eslint/type-utils@5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz#d2c02eb2bdf54d0a645ba3a173ceda78346cf248"
integrity sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==
dependencies:
"@typescript-eslint/utils" "5.15.0"
debug "^4.3.2"
tsutils "^3.21.0"
"@typescript-eslint/types@5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.15.0.tgz#c7bdd103843b1abae97b5518219d3e2a0d79a501"
integrity sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==
"@typescript-eslint/typescript-estree@5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz#81513a742a9c657587ad1ddbca88e76c6efb0aac"
integrity sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==
dependencies:
"@typescript-eslint/types" "5.15.0"
"@typescript-eslint/visitor-keys" "5.15.0"
debug "^4.3.2"
globby "^11.0.4"
is-glob "^4.0.3"
semver "^7.3.5"
tsutils "^3.21.0"
"@typescript-eslint/utils@5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.15.0.tgz#468510a0974d3ced8342f37e6c662778c277f136"
integrity sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==
dependencies:
"@types/json-schema" "^7.0.9"
"@typescript-eslint/scope-manager" "5.15.0"
"@typescript-eslint/types" "5.15.0"
"@typescript-eslint/typescript-estree" "5.15.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/visitor-keys@5.15.0":
version "5.15.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz#5669739fbf516df060f978be6a6dce75855a8027"
integrity sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==
dependencies:
"@typescript-eslint/types" "5.15.0"
eslint-visitor-keys "^3.0.0"
"@webassemblyjs/ast@1.11.1": "@webassemblyjs/ast@1.11.1":
version "1.11.1" version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@ -2243,7 +2377,7 @@ ansi-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
ansi-regex@^5.0.0: ansi-regex@^5.0.0, ansi-regex@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
@ -2866,9 +3000,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001252, caniuse-lite@^1.0.30001254: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001252, caniuse-lite@^1.0.30001254:
version "1.0.30001257" version "1.0.30001317"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz#150aaf649a48bee531104cfeda57f92ce587f6e5" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz"
integrity sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA== integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ==
catharsis@^0.9.0: catharsis@^0.9.0:
version "0.9.0" version "0.9.0"
@ -2989,6 +3123,11 @@ ci-info@^3.1.1:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6"
integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==
ci-info@^3.2.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2"
integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==
cjs-module-lexer@^1.0.0: cjs-module-lexer@^1.0.0:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40"
@ -3556,6 +3695,13 @@ debug@^3.1.1, debug@^3.2.7:
dependencies: dependencies:
ms "^2.1.1" ms "^2.1.1"
debug@^4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
decamelize-keys@^1.1.0: decamelize-keys@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
@ -3681,6 +3827,11 @@ diff-sequences@^27.0.6:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.0.6.tgz#3305cb2e55a033924054695cc66019fd7f8e5723"
integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ== integrity sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==
diff-sequences@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==
dir-glob@^3.0.1: dir-glob@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@ -4237,6 +4388,13 @@ eslint-utils@^2.1.0:
dependencies: dependencies:
eslint-visitor-keys "^1.1.0" eslint-visitor-keys "^1.1.0"
eslint-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
dependencies:
eslint-visitor-keys "^2.0.0"
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
@ -4247,6 +4405,11 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
eslint-visitor-keys@^3.0.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
eslint@^7.0.0: eslint@^7.0.0:
version "7.32.0" version "7.32.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
@ -4405,6 +4568,16 @@ expect@^27.2.0:
jest-message-util "^27.2.0" jest-message-util "^27.2.0"
jest-regex-util "^27.0.6" jest-regex-util "^27.0.6"
expect@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74"
integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==
dependencies:
"@jest/types" "^27.5.1"
jest-get-type "^27.5.1"
jest-matcher-utils "^27.5.1"
jest-message-util "^27.5.1"
express@^4.17.1: express@^4.17.1:
version "4.17.1" version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
@ -4469,6 +4642,17 @@ fast-glob@^3.1.1, fast-glob@^3.2.5:
merge2 "^1.3.0" merge2 "^1.3.0"
micromatch "^4.0.4" micromatch "^4.0.4"
fast-glob@^3.2.9:
version "3.2.11"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.2"
merge2 "^1.3.0"
micromatch "^4.0.4"
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
@ -4819,6 +5003,18 @@ globby@^11.0.1, globby@^11.0.3:
merge2 "^1.3.0" merge2 "^1.3.0"
slash "^3.0.0" slash "^3.0.0"
globby@^11.0.4:
version "11.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
dependencies:
array-union "^2.1.0"
dir-glob "^3.0.1"
fast-glob "^3.2.9"
ignore "^5.2.0"
merge2 "^1.4.1"
slash "^3.0.0"
globjoin@^0.1.4: globjoin@^0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
@ -4836,6 +5032,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0,
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
graceful-fs@^4.2.9:
version "4.2.9"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
gzip-size@^6.0.0: gzip-size@^6.0.0:
version "6.0.0" version "6.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
@ -5162,6 +5363,11 @@ ignore@^5.1.4, ignore@^5.1.8:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
ignore@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
immediate@~3.0.5: immediate@~3.0.5:
version "3.0.6" version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
@ -5832,6 +6038,16 @@ jest-diff@^27.2.0:
jest-get-type "^27.0.6" jest-get-type "^27.0.6"
pretty-format "^27.2.0" pretty-format "^27.2.0"
jest-diff@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def"
integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==
dependencies:
chalk "^4.0.0"
diff-sequences "^27.5.1"
jest-get-type "^27.5.1"
pretty-format "^27.5.1"
jest-docblock@^27.0.6: jest-docblock@^27.0.6:
version "27.0.6" version "27.0.6"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3"
@ -5880,6 +6096,11 @@ jest-get-type@^27.0.6:
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe"
integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg== integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==
jest-get-type@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==
jest-haste-map@^27.2.0: jest-haste-map@^27.2.0:
version "27.2.0" version "27.2.0"
resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.2.0.tgz#703b3a473e3f2e27d75ab07864ffd7bbaad0d75e" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.2.0.tgz#703b3a473e3f2e27d75ab07864ffd7bbaad0d75e"
@ -5942,6 +6163,16 @@ jest-matcher-utils@^27.2.0:
jest-get-type "^27.0.6" jest-get-type "^27.0.6"
pretty-format "^27.2.0" pretty-format "^27.2.0"
jest-matcher-utils@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab"
integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==
dependencies:
chalk "^4.0.0"
jest-diff "^27.5.1"
jest-get-type "^27.5.1"
pretty-format "^27.5.1"
jest-message-util@^27.2.0: jest-message-util@^27.2.0:
version "27.2.0" version "27.2.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.2.0.tgz#2f65c71df55267208686b1d7514e18106c91ceaf" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.2.0.tgz#2f65c71df55267208686b1d7514e18106c91ceaf"
@ -5957,6 +6188,21 @@ jest-message-util@^27.2.0:
slash "^3.0.0" slash "^3.0.0"
stack-utils "^2.0.3" stack-utils "^2.0.3"
jest-message-util@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf"
integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==
dependencies:
"@babel/code-frame" "^7.12.13"
"@jest/types" "^27.5.1"
"@types/stack-utils" "^2.0.0"
chalk "^4.0.0"
graceful-fs "^4.2.9"
micromatch "^4.0.4"
pretty-format "^27.5.1"
slash "^3.0.0"
stack-utils "^2.0.3"
jest-mock@^27.1.1: jest-mock@^27.1.1:
version "27.1.1" version "27.1.1"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.1.1.tgz#c7a2e81301fdcf3dab114931d23d89ec9d0c3a82" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.1.1.tgz#c7a2e81301fdcf3dab114931d23d89ec9d0c3a82"
@ -5965,6 +6211,14 @@ jest-mock@^27.1.1:
"@jest/types" "^27.1.1" "@jest/types" "^27.1.1"
"@types/node" "*" "@types/node" "*"
jest-mock@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6"
integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==
dependencies:
"@jest/types" "^27.5.1"
"@types/node" "*"
jest-pnp-resolver@^1.2.2: jest-pnp-resolver@^1.2.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
@ -6116,6 +6370,18 @@ jest-util@^27.0.0, jest-util@^27.2.0:
is-ci "^3.0.0" is-ci "^3.0.0"
picomatch "^2.2.3" picomatch "^2.2.3"
jest-util@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9"
integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==
dependencies:
"@jest/types" "^27.5.1"
"@types/node" "*"
chalk "^4.0.0"
ci-info "^3.2.0"
graceful-fs "^4.2.9"
picomatch "^2.2.3"
jest-validate@^27.2.0: jest-validate@^27.2.0:
version "27.2.0" version "27.2.0"
resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.2.0.tgz#b7535f12d95dd3b4382831f4047384ca098642ab" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.2.0.tgz#b7535f12d95dd3b4382831f4047384ca098642ab"
@ -6804,7 +7070,7 @@ merge-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.3.0: merge2@^1.3.0, merge2@^1.4.1:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
@ -7933,6 +8199,15 @@ pretty-format@^27.2.0:
ansi-styles "^5.0.0" ansi-styles "^5.0.0"
react-is "^17.0.1" react-is "^17.0.1"
pretty-format@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
dependencies:
ansi-regex "^5.0.1"
ansi-styles "^5.0.0"
react-is "^17.0.1"
process-nextick-args@~2.0.0: process-nextick-args@~2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@ -8553,7 +8828,7 @@ regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.1:
call-bind "^1.0.2" call-bind "^1.0.2"
define-properties "^1.1.3" define-properties "^1.1.3"
regexpp@^3.1.0: regexpp@^3.1.0, regexpp@^3.2.0:
version "3.2.0" version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
@ -9714,7 +9989,7 @@ tsconfig-paths@^3.12.0:
minimist "^1.2.0" minimist "^1.2.0"
strip-bom "^3.0.0" strip-bom "^3.0.0"
tslib@^1.9.0, tslib@^1.9.3: tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.14.1" version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@ -9724,6 +9999,13 @@ tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.1:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
dependencies:
tslib "^1.8.1"
twemoji-parser@13.0.0: twemoji-parser@13.0.0:
version "13.0.0" version "13.0.0"
resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.0.0.tgz#bd9d1b98474f1651dc174696b45cabefdfa405af" resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.0.0.tgz#bd9d1b98474f1651dc174696b45cabefdfa405af"