From fc520fdbdcabb7518ca20802d7fbe2e85d4f5a5b Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 15 Nov 2021 12:39:39 -0800 Subject: [PATCH 001/256] Adds quick first pass on lists stream manager --- bookwyrm/lists_stream.py | 238 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 bookwyrm/lists_stream.py diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py new file mode 100644 index 00000000..82cef5e4 --- /dev/null +++ b/bookwyrm/lists_stream.py @@ -0,0 +1,238 @@ +""" access the activity streams stored in redis """ +from django.dispatch import receiver +from django.db import transaction +from django.db.models import signals, Q + +from bookwyrm import models +from bookwyrm.redis_store import RedisStore +from bookwyrm.tasks import app, LOW, MEDIUM, HIGH + + +class ListsStream(RedisStore): + """a category of activity stream (like home, local, books)""" + + def stream_id(self, user): # pylint: disable=no-self-use + """the redis key for this user's instance of this stream""" + return f"{user.id}-lists" + + def get_rank(self, obj): # pylint: disable=no-self-use + """lists are sorted by date published""" + return obj.updated_date.timestamp() + + def add_list(self, book_list): + """add a list to users' feeds""" + # the pipeline contains all the add-to-stream activities + self.add_object_to_related_stores(book_list) + + def add_user_lists(self, viewer, user): + """add a user's listes to another user's feed""" + # only add the listes that the viewer should be able to see + lists = models.List.filter(user=user).privacy_filter(viewer) + self.bulk_add_objects_to_store(lists, self.stream_id(viewer)) + + def remove_user_lists(self, viewer, user): + """remove a user's list from another user's feed""" + # remove all so that followers only lists are removed + lists = user.list_set.all() + self.bulk_remove_objects_from_store(lists, self.stream_id(viewer)) + + def get_activity_stream(self, user): + """load the lists to be displayed""" + lists = self.get_store(self.stream_id(user)) + return ( + models.List.objects.filter(id__in=lists) + .select_related( + "user", + ) + .prefetch_related("listitem_set") + .order_by("-updated_date") + ) + + def populate_streams(self, user): + """go from zero to a timeline""" + self.populate_store(self.stream_id(user)) + + def get_audience(self, book_list): # pylint: disable=no-self-use + """given a list, what users should see it""" + # everybody who could plausibly see this list + audience = models.User.objects.filter( + is_active=True, + local=True, # we only create feeds for users of this instance + ).exclude( # not blocked + Q(id__in=book_list.user.blocks.all()) | Q(blocks=book_list.user) + ) + + # TODO: groups + + # only visible to the poster and mentioned users + if book_list.privacy == "direct": + audience = audience.filter( + Q(id=list.user.id) # if the user is the post's author + ) + # only visible to the poster's followers and tagged users + elif book_list.privacy == "followers": + audience = audience.filter( + Q(id=book_list.user.id) # if the user is the post's author + | Q(following=book_list.user) # if the user is following the author + ) + return audience.distinct() + + def get_stores_for_object(self, obj): + return [self.stream_id(u) for u in self.get_audience(obj)] + + def get_lists_for_user(self, user): # pylint: disable=no-self-use + """given a user, what lists should they see on this stream""" + return models.List.privacy_filter( + user, + privacy_levels=["public", "followers"], + ) + + def get_objects_for_store(self, store): + user = models.User.objects.get(id=store.split("-")[0]) + return self.get_lists_for_user(user) + + +@receiver(signals.post_save, sender=models.List) +# pylint: disable=unused-argument +def add_list_on_create(sender, instance, created, *args, **kwargs): + """add newly created lists to activity feeds""" + # we're only interested in new lists + if not issubclass(sender, models.List): + return + + if instance.deleted: + remove_list_task.delay(instance.id) + return + + # when creating new things, gotta wait on the transaction + transaction.on_commit(lambda: add_list_on_create_command(instance, created)) + + +def add_list_on_create_command(instance, created): + """runs this code only after the database commit completes""" + priority = HIGH + # check if this is an old list, de-prioritize if so + # (this will happen if federation is very slow, or, more expectedly, on csv import) + one_day = 60 * 60 * 24 + if (instance.created_date - instance.published_date).seconds > one_day: + priority = LOW + + add_list_task.apply_async( + args=(instance.id,), + kwargs={"increment_unread": created}, + queue=priority, + ) + + +@receiver(signals.post_save, sender=models.UserFollows) +# pylint: disable=unused-argument +def add_lists_on_follow(sender, instance, created, *args, **kwargs): + """add a newly followed user's lists to feeds""" + if not created or not instance.user_subject.local: + return + add_user_lists_task.delay( + instance.user_subject.id, instance.user_object.id, stream_list=["home"] + ) + + +@receiver(signals.post_delete, sender=models.UserFollows) +# pylint: disable=unused-argument +def remove_lists_on_unfollow(sender, instance, *args, **kwargs): + """remove lists from a feed on unfollow""" + if not instance.user_subject.local: + return + remove_user_lists_task.delay( + instance.user_subject.id, instance.user_object.id, stream_list=["home"] + ) + + +@receiver(signals.post_save, sender=models.UserBlocks) +# pylint: disable=unused-argument +def remove_lists_on_block(sender, instance, *args, **kwargs): + """remove lists from all feeds on block""" + # blocks apply ot all feeds + if instance.user_subject.local: + remove_user_lists_task.delay(instance.user_subject.id, instance.user_object.id) + + # and in both directions + if instance.user_object.local: + remove_user_lists_task.delay(instance.user_object.id, instance.user_subject.id) + + +@receiver(signals.post_delete, sender=models.UserBlocks) +# pylint: disable=unused-argument +def add_lists_on_unblock(sender, instance, *args, **kwargs): + """add lists back to all feeds on unblock""" + # make sure there isn't a block in the other direction + if models.UserBlocks.objects.filter( + user_subject=instance.user_object, + user_object=instance.user_subject, + ).exists(): + return + + # add lists back to streams with lists from anyone + if instance.user_subject.local: + add_user_lists_task.delay( + instance.user_subject.id, + instance.user_object.id, + ) + + # add lists back to streams with lists from anyone + if instance.user_object.local: + add_user_lists_task.delay( + instance.user_object.id, + instance.user_subject.id, + ) + + +@receiver(signals.post_save, sender=models.User) +# pylint: disable=unused-argument +def populate_streams_on_account_create(sender, instance, created, *args, **kwargs): + """build a user's feeds when they join""" + if not created or not instance.local: + return + + populate_lists_stream_task.delay(instance.id) + + +# ---- TASKS +@app.task(queue=MEDIUM) +def populate_lists_stream_task(user_id): + """background task for populating an empty activitystream""" + user = models.User.objects.get(id=user_id) + ListsStream().populate_streams(user) + + +@app.task(queue=MEDIUM) +def remove_list_task(list_ids): + """remove a list from any stream it might be in""" + # this can take an id or a list of ids + if not isinstance(list_ids, list): + list_ids = [list_ids] + lists = models.List.objects.filter(id__in=list_ids) + + for book_list in lists: + ListsStream().remove_object_from_related_stores(book_list) + + +@app.task(queue=HIGH) +def add_list_task(list_id): + """add a list to any stream it should be in""" + book_list = models.List.objects.get(id=list_id) + ListsStream().add_list(book_list) + + +@app.task(queue=MEDIUM) +def remove_user_lists_task(viewer_id, user_id): + """remove all lists by a user from a viewer's stream""" + viewer = models.User.objects.get(id=viewer_id) + user = models.User.objects.get(id=user_id) + ListsStream().remove_user_lists(viewer, user) + + +@app.task(queue=MEDIUM) +def add_user_lists_task(viewer_id, user_id): + """add all lists by a user to a viewer's stream""" + viewer = models.User.objects.get(id=viewer_id) + user = models.User.objects.get(id=user_id) + ListsStream().add_user_lists(viewer, user) From 1d28c7e73dff221597fe8083e8aecc2ac408cb66 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 16 Nov 2021 09:21:12 -0800 Subject: [PATCH 002/256] Load lists from redis cache --- bookwyrm/lists_stream.py | 10 ++++++---- bookwyrm/views/list.py | 16 +++------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py index 82cef5e4..1aef95bd 100644 --- a/bookwyrm/lists_stream.py +++ b/bookwyrm/lists_stream.py @@ -1,7 +1,7 @@ """ access the activity streams stored in redis """ from django.dispatch import receiver from django.db import transaction -from django.db.models import signals, Q +from django.db.models import signals, Count, Q from bookwyrm import models from bookwyrm.redis_store import RedisStore @@ -41,11 +41,13 @@ class ListsStream(RedisStore): lists = self.get_store(self.stream_id(user)) return ( models.List.objects.filter(id__in=lists) - .select_related( - "user", - ) + .annotate(item_count=Count("listitem", filter=Q(listitem__approved=True))) + # hide lists with no approved books + .filter(item_count__gt=0) + .select_related("user") .prefetch_related("listitem_set") .order_by("-updated_date") + .distinct() ) def populate_streams(self, user): diff --git a/bookwyrm/views/list.py b/bookwyrm/views/list.py index 97eaf9d6..1049f070 100644 --- a/bookwyrm/views/list.py +++ b/bookwyrm/views/list.py @@ -5,7 +5,7 @@ from urllib.parse import urlencode from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db import IntegrityError, transaction -from django.db.models import Avg, Count, DecimalField, Q, Max +from django.db.models import Avg, DecimalField, Q, Max from django.db.models.functions import Coalesce from django.http import HttpResponseBadRequest, HttpResponse from django.shortcuts import get_object_or_404, redirect @@ -17,6 +17,7 @@ from django.views.decorators.http import require_POST from bookwyrm import book_search, forms, models from bookwyrm.activitypub import ActivitypubResponse +from bookwyrm.lists_stream import ListsStream from bookwyrm.settings import PAGE_LENGTH from .helpers import is_api_request from .helpers import get_user_from_username @@ -28,18 +29,7 @@ class Lists(View): def get(self, request): """display a book list""" - # hide lists with no approved books - lists = ( - models.List.privacy_filter( - request.user, privacy_levels=["public", "followers"] - ) - .annotate(item_count=Count("listitem", filter=Q(listitem__approved=True))) - .filter(item_count__gt=0) - .select_related("user") - .prefetch_related("listitem_set") - .order_by("-updated_date") - .distinct() - ) + lists = ListsStream().get_activity_stream(request.user) paginated = Paginator(lists, 12) data = { "lists": paginated.get_page(request.GET.get("page")), From 903aaaf4c4d7664246001e1102e3a70c048a6e0c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 16 Nov 2021 10:41:08 -0800 Subject: [PATCH 003/256] Adds management and bw-dev commands --- .../commands/populate_lists_streams.py | 34 +++++++++++++++++++ .../management/commands/populate_streams.py | 6 ++-- bw-dev | 3 ++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 bookwyrm/management/commands/populate_lists_streams.py diff --git a/bookwyrm/management/commands/populate_lists_streams.py b/bookwyrm/management/commands/populate_lists_streams.py new file mode 100644 index 00000000..1cf488df --- /dev/null +++ b/bookwyrm/management/commands/populate_lists_streams.py @@ -0,0 +1,34 @@ +""" Re-create user streams """ +from django.core.management.base import BaseCommand +from bookwyrm import lists_stream, models + + +def populate_lists_streams(): + """build all the lists streams for all the users""" + print("Populating lists streams") + users = models.User.objects.filter( + local=True, + is_active=True, + ).order_by("-last_active_date") + print("This may take a long time! Please be patient.") + for user in users: + print(".", end="") + lists_stream.populate_lists_stream_task.delay(user.id) + + +class Command(BaseCommand): + """start all over with user streams""" + + help = "Populate streams for all users" + + def add_arguments(self, parser): + parser.add_argument( + "--stream", + default=None, + help="Specifies which time of stream to populate", + ) + + # pylint: disable=no-self-use,unused-argument + def handle(self, *args, **options): + """run feed builder""" + populate_lists_streams() diff --git a/bookwyrm/management/commands/populate_streams.py b/bookwyrm/management/commands/populate_streams.py index a04d7f5a..6b537650 100644 --- a/bookwyrm/management/commands/populate_streams.py +++ b/bookwyrm/management/commands/populate_streams.py @@ -1,18 +1,20 @@ """ Re-create user streams """ from django.core.management.base import BaseCommand -from bookwyrm import activitystreams, models +from bookwyrm import activitystreams, lists_stream, models def populate_streams(stream=None): """build all the streams for all the users""" streams = [stream] if stream else activitystreams.streams.keys() - print("Populations streams", streams) + print("Populating streams", streams) users = models.User.objects.filter( local=True, is_active=True, ).order_by("-last_active_date") print("This may take a long time! Please be patient.") for user in users: + print(".", end="") + lists_stream.populate_lists_stream_task.delay(user.id) for stream_key in streams: print(".", end="") activitystreams.populate_stream_task.delay(stream_key, user.id) diff --git a/bw-dev b/bw-dev index 35f3694e..c5ae7c9e 100755 --- a/bw-dev +++ b/bw-dev @@ -120,6 +120,9 @@ case "$CMD" in populate_streams) runweb python manage.py populate_streams $@ ;; + populate_lists_streams) + runweb python manage.py populate_lists_streams $@ + ;; populate_suggestions) runweb python manage.py populate_suggestions ;; From 4cb572f4c7f78c6a8288b72cbb3b310905e72033 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 16 Nov 2021 11:17:49 -0800 Subject: [PATCH 004/256] Updates management tests --- .../management/test_populate_lists_streams.py | 54 +++++++++++++++++++ .../tests/management/test_populate_streams.py | 15 +++++- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 bookwyrm/tests/management/test_populate_lists_streams.py diff --git a/bookwyrm/tests/management/test_populate_lists_streams.py b/bookwyrm/tests/management/test_populate_lists_streams.py new file mode 100644 index 00000000..0a586d86 --- /dev/null +++ b/bookwyrm/tests/management/test_populate_lists_streams.py @@ -0,0 +1,54 @@ +""" test populating user streams """ +from unittest.mock import patch +from django.test import TestCase + +from bookwyrm import models +from bookwyrm.management.commands.populate_lists_streams import populate_lists_streams + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +class Activitystreams(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """we need some stuff""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "nutria", + "nutria@nutria.nutria", + "password", + local=True, + localname="nutria", + ) + models.User.objects.create_user( + "gerbil", + "gerbil@nutria.nutria", + "password", + local=True, + localname="gerbil", + is_active=False, + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + self.book = models.Edition.objects.create(title="test book") + + def test_populate_streams(self, _): + """make sure the function on the redis manager gets called""" + with patch( + "bookwyrm.lists_stream.populate_lists_stream_task.delay" + ) as list_mock: + populate_lists_streams() + self.assertEqual(list_mock.call_count, 2) # 2 users diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index 5be1774d..cee8b381 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -25,6 +25,14 @@ class Activitystreams(TestCase): local=True, localname="nutria", ) + models.User.objects.create_user( + "gerbil", + "gerbil@gerbil.gerbil", + "password", + local=True, + localname="gerbil", + is_active=False, + ) with patch("bookwyrm.models.user.set_remote_server.delay"): self.remote_user = models.User.objects.create_user( "rat", @@ -44,6 +52,11 @@ class Activitystreams(TestCase): user=self.local_user, content="hi", book=self.book ) - with patch("bookwyrm.activitystreams.populate_stream_task.delay") as redis_mock: + with patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ) as redis_mock, patch( + "bookwyrm.lists_stream.populate_lists_stream_task.delay" + ) as list_mock: populate_streams() self.assertEqual(redis_mock.call_count, 6) # 2 users x 3 streams + self.assertEqual(list_mock.call_count, 2) # 2 users From 157d8916813d8718b9ad5c31a35ac2678029e926 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 17 Nov 2021 09:10:28 -0800 Subject: [PATCH 005/256] Adds tests files --- bookwyrm/lists_stream.py | 17 +- bookwyrm/tests/lists_stream/__init__.py | 1 + bookwyrm/tests/lists_stream/test_signals.py | 118 +++++++++++ bookwyrm/tests/lists_stream/test_stream.py | 113 ++++++++++ bookwyrm/tests/lists_stream/test_tasks.py | 218 ++++++++++++++++++++ 5 files changed, 458 insertions(+), 9 deletions(-) create mode 100644 bookwyrm/tests/lists_stream/__init__.py create mode 100644 bookwyrm/tests/lists_stream/test_signals.py create mode 100644 bookwyrm/tests/lists_stream/test_stream.py create mode 100644 bookwyrm/tests/lists_stream/test_tasks.py diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py index 1aef95bd..ec6726a9 100644 --- a/bookwyrm/lists_stream.py +++ b/bookwyrm/lists_stream.py @@ -69,7 +69,7 @@ class ListsStream(RedisStore): # only visible to the poster and mentioned users if book_list.privacy == "direct": audience = audience.filter( - Q(id=list.user.id) # if the user is the post's author + Q(id=book_list.user.id) # if the user is the post's author ) # only visible to the poster's followers and tagged users elif book_list.privacy == "followers": @@ -98,18 +98,17 @@ class ListsStream(RedisStore): # pylint: disable=unused-argument def add_list_on_create(sender, instance, created, *args, **kwargs): """add newly created lists to activity feeds""" - # we're only interested in new lists - if not issubclass(sender, models.List): - return - - if instance.deleted: - remove_list_task.delay(instance.id) - return - # when creating new things, gotta wait on the transaction transaction.on_commit(lambda: add_list_on_create_command(instance, created)) +@receiver(signals.pre_delete, sender=models.List) +# pylint: disable=unused-argument +def remove_list_on_delete(sender, instance, created, *args, **kwargs): + """add newly created lists to activity feeds""" + remove_list_task.delay(instance.id) + + def add_list_on_create_command(instance, created): """runs this code only after the database commit completes""" priority = HIGH diff --git a/bookwyrm/tests/lists_stream/__init__.py b/bookwyrm/tests/lists_stream/__init__.py new file mode 100644 index 00000000..b6e690fd --- /dev/null +++ b/bookwyrm/tests/lists_stream/__init__.py @@ -0,0 +1 @@ +from . import * diff --git a/bookwyrm/tests/lists_stream/test_signals.py b/bookwyrm/tests/lists_stream/test_signals.py new file mode 100644 index 00000000..34aeb947 --- /dev/null +++ b/bookwyrm/tests/lists_stream/test_signals.py @@ -0,0 +1,118 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +class ActivitystreamsSignals(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """use a test csv""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "fish", "fish@fish.fish", "password", local=True, localname="fish" + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + work = models.Work.objects.create(title="test work") + self.book = models.Edition.objects.create(title="test book", parent_work=work) + + def test_add_status_on_create_ignore(self, _): + """a new statuses has entered""" + activitystreams.add_status_on_create(models.User, self.local_user, False) + + def test_add_status_on_create_deleted(self, _): + """a new statuses has entered""" + with patch("bookwyrm.activitystreams.remove_status_task.delay"): + status = models.Status.objects.create( + user=self.remote_user, content="hi", privacy="public", deleted=True + ) + with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock: + activitystreams.add_status_on_create(models.Status, status, False) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], status.id) + + def test_add_status_on_create_created(self, _): + """a new statuses has entered""" + status = models.Status.objects.create( + user=self.remote_user, content="hi", privacy="public" + ) + with patch("bookwyrm.activitystreams.add_status_task.apply_async") as mock: + activitystreams.add_status_on_create_command(models.Status, status, False) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[1] + self.assertEqual(args["args"][0], status.id) + self.assertEqual(args["queue"], "high_priority") + + def test_populate_streams_on_account_create(self, _): + """create streams for a user""" + with patch("bookwyrm.activitystreams.populate_stream_task.delay") as mock: + activitystreams.populate_streams_on_account_create( + models.User, self.local_user, True + ) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], "books") + self.assertEqual(args[1], self.local_user.id) + + def test_remove_statuses_on_block(self, _): + """don't show statuses from blocked users""" + with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") as mock: + models.UserBlocks.objects.create( + user_subject=self.local_user, + user_object=self.remote_user, + ) + + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user.id) + self.assertEqual(args[1], self.remote_user.id) + + def test_add_statuses_on_unblock(self, _): + """re-add statuses on unblock""" + with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): + block = models.UserBlocks.objects.create( + user_subject=self.local_user, + user_object=self.remote_user, + ) + + with patch("bookwyrm.activitystreams.add_user_statuses_task.delay") as mock: + block.delete() + + args = mock.call_args[0] + kwargs = mock.call_args.kwargs + self.assertEqual(args[0], self.local_user.id) + self.assertEqual(args[1], self.remote_user.id) + self.assertEqual(kwargs["stream_list"], ["local", "books"]) + + def test_add_statuses_on_unblock_reciprocal_block(self, _): + """re-add statuses on unblock""" + with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): + block = models.UserBlocks.objects.create( + user_subject=self.local_user, + user_object=self.remote_user, + ) + block = models.UserBlocks.objects.create( + user_subject=self.remote_user, + user_object=self.local_user, + ) + + with patch("bookwyrm.activitystreams.add_user_statuses_task.delay") as mock: + block.delete() + + self.assertEqual(mock.call_count, 0) diff --git a/bookwyrm/tests/lists_stream/test_stream.py b/bookwyrm/tests/lists_stream/test_stream.py new file mode 100644 index 00000000..25241793 --- /dev/null +++ b/bookwyrm/tests/lists_stream/test_stream.py @@ -0,0 +1,113 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import lists_stream, models + + +@patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +@patch("bookwyrm.activitystreams.add_status_task.delay") +@patch("bookwyrm.activitystreams.add_book_statuses_task.delay") +@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") +class ListsStream(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """use a test csv""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "nutria", + "nutria@nutria.nutria", + "password", + local=True, + localname="nutria", + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + self.stream = lists_stream.ListsStream() + + def test_lists_stream_ids(self, *_): + """the abstract base class for stream objects""" + self.assertEqual( + self.stream.stream_id(self.local_user), + f"{self.local_user.id}-lists", + ) + + def test_get_audience(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + users = self.stream.get_audience(book_list) + # remote users don't have feeds + self.assertFalse(self.remote_user in users) + self.assertTrue(self.local_user in users) + self.assertTrue(self.another_user in users) + + def test_get_audience_direct(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.remote_user, + name="hi", + privacy="direct", + ) + users = self.stream.get_audience(book_list) + self.assertFalse(users.exists()) + + book_list = models.List.objects.create( + user=self.local_user, + name="hi", + privacy="direct", + ) + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) + + def test_get_audience_followers_remote_user(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.remote_user, + name="hi", + privacy="followers", + ) + users = self.stream.get_audience(book_list) + self.assertFalse(users.exists()) + + def test_get_audience_followers_self(self, *_): + """get a list of users that should see a list""" + book_list = models.List.objects.create( + user=self.local_user, + name="hi", + privacy="direct", + ) + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) + + def test_get_audience_followers_with_relationship(self, *_): + """get a list of users that should see a list""" + self.remote_user.followers.add(self.local_user) + book_list = models.List.objects.create( + user=self.remote_user, + name="hi", + privacy="direct", + ) + users = self.stream.get_audience(book_list) + self.assertFalse(self.local_user in users) + self.assertFalse(self.another_user in users) + self.assertFalse(self.remote_user in users) diff --git a/bookwyrm/tests/lists_stream/test_tasks.py b/bookwyrm/tests/lists_stream/test_tasks.py new file mode 100644 index 00000000..f5750763 --- /dev/null +++ b/bookwyrm/tests/lists_stream/test_tasks.py @@ -0,0 +1,218 @@ +""" testing activitystreams """ +from unittest.mock import patch +from django.test import TestCase +from bookwyrm import activitystreams, models + + +class Activitystreams(TestCase): + """using redis to build activity streams""" + + def setUp(self): + """use a test csv""" + with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( + "bookwyrm.activitystreams.populate_stream_task.delay" + ): + self.local_user = models.User.objects.create_user( + "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" + ) + self.another_user = models.User.objects.create_user( + "nutria", + "nutria@nutria.nutria", + "password", + local=True, + localname="nutria", + ) + with patch("bookwyrm.models.user.set_remote_server.delay"): + self.remote_user = models.User.objects.create_user( + "rat", + "rat@rat.com", + "ratword", + local=False, + remote_id="https://example.com/users/rat", + inbox="https://example.com/users/rat/inbox", + outbox="https://example.com/users/rat/outbox", + ) + work = models.Work.objects.create(title="test work") + self.book = models.Edition.objects.create(title="test book", parent_work=work) + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + self.status = models.Status.objects.create( + content="hi", user=self.local_user + ) + + def test_add_book_statuses_task(self): + """statuses related to a book""" + with patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") as mock: + activitystreams.add_book_statuses_task(self.local_user.id, self.book.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.book) + + def test_remove_book_statuses_task(self): + """remove stauses related to a book""" + with patch("bookwyrm.activitystreams.BooksStream.remove_book_statuses") as mock: + activitystreams.remove_book_statuses_task(self.local_user.id, self.book.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.book) + + def test_populate_stream_task(self): + """populate a given stream""" + with patch("bookwyrm.activitystreams.BooksStream.populate_streams") as mock: + activitystreams.populate_stream_task("books", self.local_user.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + + with patch("bookwyrm.activitystreams.HomeStream.populate_streams") as mock: + activitystreams.populate_stream_task("home", self.local_user.id) + self.assertTrue(mock.called) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + + def test_remove_status_task(self): + """remove a status from all streams""" + with patch( + "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" + ) as mock: + activitystreams.remove_status_task(self.status.id) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.status) + + def test_add_status_task(self): + """add a status to all streams""" + with patch("bookwyrm.activitystreams.ActivityStream.add_status") as mock: + activitystreams.add_status_task(self.status.id) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.status) + + def test_remove_user_statuses_task(self): + """remove all statuses by a user from another users' feeds""" + with patch( + "bookwyrm.activitystreams.ActivityStream.remove_user_statuses" + ) as mock: + activitystreams.remove_user_statuses_task( + self.local_user.id, self.another_user.id + ) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + with patch("bookwyrm.activitystreams.HomeStream.remove_user_statuses") as mock: + activitystreams.remove_user_statuses_task( + self.local_user.id, self.another_user.id, stream_list=["home"] + ) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + def test_add_user_statuses_task(self): + """add a user's statuses to another users feeds""" + with patch("bookwyrm.activitystreams.ActivityStream.add_user_statuses") as mock: + activitystreams.add_user_statuses_task( + self.local_user.id, self.another_user.id + ) + self.assertEqual(mock.call_count, 3) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + with patch("bookwyrm.activitystreams.HomeStream.add_user_statuses") as mock: + activitystreams.add_user_statuses_task( + self.local_user.id, self.another_user.id, stream_list=["home"] + ) + self.assertEqual(mock.call_count, 1) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) + + @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") + def test_boost_to_another_timeline(self, *_): + """boost from a non-follower doesn't remove original status from feed""" + status = models.Status.objects.create(user=self.local_user, content="hi") + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): + boost = models.Boost.objects.create( + boosted_status=status, + user=self.another_user, + ) + with patch( + "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" + ) as mock: + activitystreams.handle_boost_task(boost.id) + + self.assertTrue(mock.called) + self.assertEqual(mock.call_count, 1) + call_args = mock.call_args + self.assertEqual(call_args[0][0], status) + self.assertEqual(call_args[1]["stores"], [f"{self.another_user.id}-home"]) + + @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") + def test_boost_to_another_timeline_remote(self, *_): + """boost from a remote non-follower doesn't remove original status from feed""" + status = models.Status.objects.create(user=self.local_user, content="hi") + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): + boost = models.Boost.objects.create( + boosted_status=status, + user=self.remote_user, + ) + with patch( + "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" + ) as mock: + activitystreams.handle_boost_task(boost.id) + + self.assertTrue(mock.called) + self.assertEqual(mock.call_count, 1) + call_args = mock.call_args + self.assertEqual(call_args[0][0], status) + self.assertEqual(call_args[1]["stores"], []) + + @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") + def test_boost_to_following_timeline(self, *_): + """add a boost and deduplicate the boosted status on the timeline""" + self.local_user.following.add(self.another_user) + status = models.Status.objects.create(user=self.local_user, content="hi") + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): + boost = models.Boost.objects.create( + boosted_status=status, + user=self.another_user, + ) + with patch( + "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" + ) as mock: + activitystreams.handle_boost_task(boost.id) + self.assertTrue(mock.called) + call_args = mock.call_args + self.assertEqual(call_args[0][0], status) + self.assertTrue(f"{self.another_user.id}-home" in call_args[1]["stores"]) + self.assertTrue(f"{self.local_user.id}-home" in call_args[1]["stores"]) + + @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") + @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") + @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") + def test_boost_to_same_timeline(self, *_): + """add a boost and deduplicate the boosted status on the timeline""" + status = models.Status.objects.create(user=self.local_user, content="hi") + with patch("bookwyrm.activitystreams.handle_boost_task.delay"): + boost = models.Boost.objects.create( + boosted_status=status, + user=self.local_user, + ) + with patch( + "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" + ) as mock: + activitystreams.handle_boost_task(boost.id) + self.assertTrue(mock.called) + call_args = mock.call_args + self.assertEqual(call_args[0][0], status) + self.assertEqual(call_args[1]["stores"], [f"{self.local_user.id}-home"]) From 3bf1121fa64f6b854f0a0a22ed346a12ffa1c154 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 17 Nov 2021 09:38:02 -0800 Subject: [PATCH 006/256] Signals tests --- bookwyrm/lists_stream.py | 29 +++---- bookwyrm/tests/lists_stream/test_signals.py | 84 +++++++++------------ 2 files changed, 46 insertions(+), 67 deletions(-) diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py index ec6726a9..04a0725c 100644 --- a/bookwyrm/lists_stream.py +++ b/bookwyrm/lists_stream.py @@ -5,7 +5,7 @@ from django.db.models import signals, Count, Q from bookwyrm import models from bookwyrm.redis_store import RedisStore -from bookwyrm.tasks import app, LOW, MEDIUM, HIGH +from bookwyrm.tasks import app, MEDIUM, HIGH class ListsStream(RedisStore): @@ -98,31 +98,22 @@ class ListsStream(RedisStore): # pylint: disable=unused-argument def add_list_on_create(sender, instance, created, *args, **kwargs): """add newly created lists to activity feeds""" + if not created: + return # when creating new things, gotta wait on the transaction - transaction.on_commit(lambda: add_list_on_create_command(instance, created)) + transaction.on_commit(lambda: add_list_on_create_command(instance)) @receiver(signals.pre_delete, sender=models.List) # pylint: disable=unused-argument -def remove_list_on_delete(sender, instance, created, *args, **kwargs): +def remove_list_on_delete(sender, instance, *args, **kwargs): """add newly created lists to activity feeds""" remove_list_task.delay(instance.id) -def add_list_on_create_command(instance, created): +def add_list_on_create_command(instance): """runs this code only after the database commit completes""" - priority = HIGH - # check if this is an old list, de-prioritize if so - # (this will happen if federation is very slow, or, more expectedly, on csv import) - one_day = 60 * 60 * 24 - if (instance.created_date - instance.published_date).seconds > one_day: - priority = LOW - - add_list_task.apply_async( - args=(instance.id,), - kwargs={"increment_unread": created}, - queue=priority, - ) + add_list_task.delay(instance.id) @receiver(signals.post_save, sender=models.UserFollows) @@ -188,17 +179,17 @@ def add_lists_on_unblock(sender, instance, *args, **kwargs): @receiver(signals.post_save, sender=models.User) # pylint: disable=unused-argument -def populate_streams_on_account_create(sender, instance, created, *args, **kwargs): +def populate_lists_on_account_create(sender, instance, created, *args, **kwargs): """build a user's feeds when they join""" if not created or not instance.local: return - populate_lists_stream_task.delay(instance.id) + populate_lists_task.delay(instance.id) # ---- TASKS @app.task(queue=MEDIUM) -def populate_lists_stream_task(user_id): +def populate_lists_task(user_id): """background task for populating an empty activitystream""" user = models.User.objects.get(id=user_id) ListsStream().populate_streams(user) diff --git a/bookwyrm/tests/lists_stream/test_signals.py b/bookwyrm/tests/lists_stream/test_signals.py index 34aeb947..7640ea98 100644 --- a/bookwyrm/tests/lists_stream/test_signals.py +++ b/bookwyrm/tests/lists_stream/test_signals.py @@ -1,11 +1,11 @@ -""" testing activitystreams """ +""" testing lists_stream """ from unittest.mock import patch from django.test import TestCase -from bookwyrm import activitystreams, models +from bookwyrm import lists_stream, models @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") -class ActivitystreamsSignals(TestCase): +class ListsStreamSignals(TestCase): """using redis to build activity streams""" def setUp(self): @@ -29,51 +29,41 @@ class ActivitystreamsSignals(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - work = models.Work.objects.create(title="test work") - self.book = models.Edition.objects.create(title="test book", parent_work=work) - def test_add_status_on_create_ignore(self, _): - """a new statuses has entered""" - activitystreams.add_status_on_create(models.User, self.local_user, False) - - def test_add_status_on_create_deleted(self, _): - """a new statuses has entered""" - with patch("bookwyrm.activitystreams.remove_status_task.delay"): - status = models.Status.objects.create( - user=self.remote_user, content="hi", privacy="public", deleted=True - ) - with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock: - activitystreams.add_status_on_create(models.Status, status, False) + def test_add_list_on_create(self, _): + """a new lists has entered""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" + ) + with patch("bookwyrm.lists_stream.add_list_task.delay") as mock: + lists_stream.add_list_on_create_command(book_list) self.assertEqual(mock.call_count, 1) args = mock.call_args[0] - self.assertEqual(args[0], status.id) + self.assertEqual(args[0], book_list.id) - def test_add_status_on_create_created(self, _): - """a new statuses has entered""" - status = models.Status.objects.create( - user=self.remote_user, content="hi", privacy="public" + def test_remove_list_on_delete(self, _): + """delete a list""" + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="public" ) - with patch("bookwyrm.activitystreams.add_status_task.apply_async") as mock: - activitystreams.add_status_on_create_command(models.Status, status, False) - self.assertEqual(mock.call_count, 1) - args = mock.call_args[1] - self.assertEqual(args["args"][0], status.id) - self.assertEqual(args["queue"], "high_priority") + with patch("bookwyrm.lists_stream.remove_list_task.delay") as mock: + lists_stream.remove_list_on_delete(models.List, book_list) + args = mock.call_args[0] + self.assertEqual(args[0], book_list.id) - def test_populate_streams_on_account_create(self, _): + def test_populate_lists_on_account_create(self, _): """create streams for a user""" - with patch("bookwyrm.activitystreams.populate_stream_task.delay") as mock: - activitystreams.populate_streams_on_account_create( + with patch("bookwyrm.lists_stream.populate_lists_task.delay") as mock: + lists_stream.populate_lists_on_account_create( models.User, self.local_user, True ) - self.assertEqual(mock.call_count, 3) + self.assertEqual(mock.call_count, 1) args = mock.call_args[0] - self.assertEqual(args[0], "books") - self.assertEqual(args[1], self.local_user.id) + self.assertEqual(args[0], self.local_user.id) - def test_remove_statuses_on_block(self, _): - """don't show statuses from blocked users""" - with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") as mock: + def test_remove_lists_on_block(self, _): + """don't show lists from blocked users""" + with patch("bookwyrm.lists_stream.remove_user_lists_task.delay") as mock: models.UserBlocks.objects.create( user_subject=self.local_user, user_object=self.remote_user, @@ -83,26 +73,24 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args[0], self.local_user.id) self.assertEqual(args[1], self.remote_user.id) - def test_add_statuses_on_unblock(self, _): - """re-add statuses on unblock""" - with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): + def test_add_lists_on_unblock(self, _): + """re-add lists on unblock""" + with patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): block = models.UserBlocks.objects.create( user_subject=self.local_user, user_object=self.remote_user, ) - with patch("bookwyrm.activitystreams.add_user_statuses_task.delay") as mock: + with patch("bookwyrm.lists_stream.add_user_lists_task.delay") as mock: block.delete() args = mock.call_args[0] - kwargs = mock.call_args.kwargs self.assertEqual(args[0], self.local_user.id) self.assertEqual(args[1], self.remote_user.id) - self.assertEqual(kwargs["stream_list"], ["local", "books"]) - def test_add_statuses_on_unblock_reciprocal_block(self, _): - """re-add statuses on unblock""" - with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): + def test_add_lists_on_unblock_reciprocal_block(self, _): + """dont' re-add lists on unblock if there's a block the other way""" + with patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): block = models.UserBlocks.objects.create( user_subject=self.local_user, user_object=self.remote_user, @@ -112,7 +100,7 @@ class ActivitystreamsSignals(TestCase): user_object=self.local_user, ) - with patch("bookwyrm.activitystreams.add_user_statuses_task.delay") as mock: + with patch("bookwyrm.lists_stream.add_user_lists_task.delay") as mock: block.delete() - self.assertEqual(mock.call_count, 0) + self.assertFalse(mock.called) From b206aae32be8e21c9bd2780f9617d4a9d7cfcab2 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Wed, 17 Nov 2021 09:47:24 -0800 Subject: [PATCH 007/256] Tasks tests --- bookwyrm/tests/lists_stream/test_tasks.py | 195 +++++----------------- 1 file changed, 41 insertions(+), 154 deletions(-) diff --git a/bookwyrm/tests/lists_stream/test_tasks.py b/bookwyrm/tests/lists_stream/test_tasks.py index f5750763..1e5f7a98 100644 --- a/bookwyrm/tests/lists_stream/test_tasks.py +++ b/bookwyrm/tests/lists_stream/test_tasks.py @@ -1,7 +1,7 @@ -""" testing activitystreams """ +""" testing lists_stream """ from unittest.mock import patch from django.test import TestCase -from bookwyrm import activitystreams, models +from bookwyrm import lists_stream, models class Activitystreams(TestCase): @@ -32,187 +32,74 @@ class Activitystreams(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - work = models.Work.objects.create(title="test work") - self.book = models.Edition.objects.create(title="test book", parent_work=work) - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - self.status = models.Status.objects.create( - content="hi", user=self.local_user - ) + self.list = models.List.objects.create( + user=self.local_user, name="hi", privacy="public" + ) - def test_add_book_statuses_task(self): - """statuses related to a book""" - with patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") as mock: - activitystreams.add_book_statuses_task(self.local_user.id, self.book.id) - self.assertTrue(mock.called) - args = mock.call_args[0] - self.assertEqual(args[0], self.local_user) - self.assertEqual(args[1], self.book) - - def test_remove_book_statuses_task(self): - """remove stauses related to a book""" - with patch("bookwyrm.activitystreams.BooksStream.remove_book_statuses") as mock: - activitystreams.remove_book_statuses_task(self.local_user.id, self.book.id) - self.assertTrue(mock.called) - args = mock.call_args[0] - self.assertEqual(args[0], self.local_user) - self.assertEqual(args[1], self.book) - - def test_populate_stream_task(self): - """populate a given stream""" - with patch("bookwyrm.activitystreams.BooksStream.populate_streams") as mock: - activitystreams.populate_stream_task("books", self.local_user.id) + def test_populate_lists_task(self): + """populate lists cache""" + with patch("bookwyrm.lists_stream.ListsStream.populate_streams") as mock: + lists_stream.populate_lists_task(self.local_user.id) self.assertTrue(mock.called) args = mock.call_args[0] self.assertEqual(args[0], self.local_user) - with patch("bookwyrm.activitystreams.HomeStream.populate_streams") as mock: - activitystreams.populate_stream_task("home", self.local_user.id) + with patch("bookwyrm.lists_stream.ListsStream.populate_streams") as mock: + lists_stream.populate_lists_task(self.local_user.id) self.assertTrue(mock.called) args = mock.call_args[0] self.assertEqual(args[0], self.local_user) - def test_remove_status_task(self): - """remove a status from all streams""" + def test_remove_list_task(self): + """remove a list from all streams""" with patch( - "bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores" + "bookwyrm.lists_stream.ListsStream.remove_object_from_related_stores" ) as mock: - activitystreams.remove_status_task(self.status.id) - self.assertEqual(mock.call_count, 3) + lists_stream.remove_list_task(self.list.id) + self.assertEqual(mock.call_count, 1) args = mock.call_args[0] - self.assertEqual(args[0], self.status) + self.assertEqual(args[0], self.list) - def test_add_status_task(self): - """add a status to all streams""" - with patch("bookwyrm.activitystreams.ActivityStream.add_status") as mock: - activitystreams.add_status_task(self.status.id) - self.assertEqual(mock.call_count, 3) + def test_add_list_task(self): + """add a list to all streams""" + with patch("bookwyrm.lists_stream.ListsStream.add_list") as mock: + lists_stream.add_list_task(self.list.id) + self.assertEqual(mock.call_count, 1) args = mock.call_args[0] - self.assertEqual(args[0], self.status) + self.assertEqual(args[0], self.list) - def test_remove_user_statuses_task(self): - """remove all statuses by a user from another users' feeds""" - with patch( - "bookwyrm.activitystreams.ActivityStream.remove_user_statuses" - ) as mock: - activitystreams.remove_user_statuses_task( + def test_remove_user_lists_task(self): + """remove all lists by a user from another users' feeds""" + with patch("bookwyrm.lists_stream.ListsStream.remove_user_lists") as mock: + lists_stream.remove_user_lists_task( self.local_user.id, self.another_user.id ) - self.assertEqual(mock.call_count, 3) - args = mock.call_args[0] - self.assertEqual(args[0], self.local_user) - self.assertEqual(args[1], self.another_user) - - with patch("bookwyrm.activitystreams.HomeStream.remove_user_statuses") as mock: - activitystreams.remove_user_statuses_task( - self.local_user.id, self.another_user.id, stream_list=["home"] - ) self.assertEqual(mock.call_count, 1) args = mock.call_args[0] self.assertEqual(args[0], self.local_user) self.assertEqual(args[1], self.another_user) - def test_add_user_statuses_task(self): - """add a user's statuses to another users feeds""" - with patch("bookwyrm.activitystreams.ActivityStream.add_user_statuses") as mock: - activitystreams.add_user_statuses_task( + with patch("bookwyrm.lists_stream.ListsStream.remove_user_lists") as mock: + lists_stream.remove_user_lists_task( self.local_user.id, self.another_user.id ) - self.assertEqual(mock.call_count, 3) - args = mock.call_args[0] - self.assertEqual(args[0], self.local_user) - self.assertEqual(args[1], self.another_user) - - with patch("bookwyrm.activitystreams.HomeStream.add_user_statuses") as mock: - activitystreams.add_user_statuses_task( - self.local_user.id, self.another_user.id, stream_list=["home"] - ) self.assertEqual(mock.call_count, 1) args = mock.call_args[0] self.assertEqual(args[0], self.local_user) self.assertEqual(args[1], self.another_user) - @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") - @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_boost_to_another_timeline(self, *_): - """boost from a non-follower doesn't remove original status from feed""" - status = models.Status.objects.create(user=self.local_user, content="hi") - with patch("bookwyrm.activitystreams.handle_boost_task.delay"): - boost = models.Boost.objects.create( - boosted_status=status, - user=self.another_user, - ) - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ) as mock: - activitystreams.handle_boost_task(boost.id) - - self.assertTrue(mock.called) + def test_add_user_lists_task(self): + """add a user's lists to another users feeds""" + with patch("bookwyrm.lists_stream.ListsStream.add_user_lists") as mock: + lists_stream.add_user_lists_task(self.local_user.id, self.another_user.id) self.assertEqual(mock.call_count, 1) - call_args = mock.call_args - self.assertEqual(call_args[0][0], status) - self.assertEqual(call_args[1]["stores"], [f"{self.another_user.id}-home"]) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) - @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") - @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_boost_to_another_timeline_remote(self, *_): - """boost from a remote non-follower doesn't remove original status from feed""" - status = models.Status.objects.create(user=self.local_user, content="hi") - with patch("bookwyrm.activitystreams.handle_boost_task.delay"): - boost = models.Boost.objects.create( - boosted_status=status, - user=self.remote_user, - ) - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ) as mock: - activitystreams.handle_boost_task(boost.id) - - self.assertTrue(mock.called) + with patch("bookwyrm.lists_stream.ListsStream.add_user_lists") as mock: + lists_stream.add_user_lists_task(self.local_user.id, self.another_user.id) self.assertEqual(mock.call_count, 1) - call_args = mock.call_args - self.assertEqual(call_args[0][0], status) - self.assertEqual(call_args[1]["stores"], []) - - @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") - @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_boost_to_following_timeline(self, *_): - """add a boost and deduplicate the boosted status on the timeline""" - self.local_user.following.add(self.another_user) - status = models.Status.objects.create(user=self.local_user, content="hi") - with patch("bookwyrm.activitystreams.handle_boost_task.delay"): - boost = models.Boost.objects.create( - boosted_status=status, - user=self.another_user, - ) - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ) as mock: - activitystreams.handle_boost_task(boost.id) - self.assertTrue(mock.called) - call_args = mock.call_args - self.assertEqual(call_args[0][0], status) - self.assertTrue(f"{self.another_user.id}-home" in call_args[1]["stores"]) - self.assertTrue(f"{self.local_user.id}-home" in call_args[1]["stores"]) - - @patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores") - @patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores") - @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_boost_to_same_timeline(self, *_): - """add a boost and deduplicate the boosted status on the timeline""" - status = models.Status.objects.create(user=self.local_user, content="hi") - with patch("bookwyrm.activitystreams.handle_boost_task.delay"): - boost = models.Boost.objects.create( - boosted_status=status, - user=self.local_user, - ) - with patch( - "bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores" - ) as mock: - activitystreams.handle_boost_task(boost.id) - self.assertTrue(mock.called) - call_args = mock.call_args - self.assertEqual(call_args[0][0], status) - self.assertEqual(call_args[1]["stores"], [f"{self.local_user.id}-home"]) + args = mock.call_args[0] + self.assertEqual(args[0], self.local_user) + self.assertEqual(args[1], self.another_user) From 4ed4278826d3e88bc544f22159aa6bb0b16fbe75 Mon Sep 17 00:00:00 2001 From: Joachim Date: Sat, 27 Nov 2021 19:18:20 +0100 Subject: [PATCH 008/256] Tidy header for non-authenticated visitors with the help of a login modal --- bookwyrm/static/css/bookwyrm.css | 16 +++++++ bookwyrm/static/js/bookwyrm.js | 74 ++++++++++++++++++++++++++++++++ bookwyrm/templates/layout.html | 71 +++++++++++++++++++++--------- 3 files changed, 141 insertions(+), 20 deletions(-) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 0d280fd5..81f0cf1a 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -25,10 +25,26 @@ body { overflow-x: auto; } +.modal-card:focus { + outline-style: auto; +} +.modal-card:focus:not(:focus-visible) { + outline-style: initial; +} +.modal-card:focus-visible { + outline-style: auto; +} + .modal-card.is-fullwidth { min-width: 75% !important; } +@media only screen and (min-width: 769px) { + .modal-card.is-thin { + width: 350px !important; + } +} + .modal-card-body { max-height: 70vh; } diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 2d5b88ad..5f062f78 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -45,6 +45,12 @@ let BookWyrm = new class { 'change', this.disableIfTooLarge.bind(this) )); + + document.querySelectorAll('button[data-modal-open]') + .forEach(node => node.addEventListener( + 'click', + this.handleModalButton.bind(this) + )); } /** @@ -368,4 +374,72 @@ let BookWyrm = new class { ); } } + + handleModalButton(element) { + const modalButton = element.currentTarget; + const targetModalId = modalButton.dataset.modalOpen; + const htmlElement = document.querySelector('html'); + + // Helper functions + function handleModalOpen(modalElement) { + htmlElement.classList.add('is-clipped'); + modalElement.classList.add('is-active'); + modalElement.getElementsByClassName('modal-card')[0].focus(); + + const closeButtons = modalElement.querySelectorAll("[data-modal-close]"); + closeButtons.forEach((button) => { + button.addEventListener( + 'click', + function() { handleModalClose(modalElement) }, + ); + }); + + document.addEventListener( + 'keydown', + function(event) { + if (event.key === 'Escape') { + handleModalClose(modalElement); + } + }, + ); + + modalElement.addEventListener('keydown', handleFocusTrap) + } + + function handleModalClose(modalElement) { + modalElement.removeEventListener('keydown', handleFocusTrap) + htmlElement.classList.remove('is-clipped'); + modalElement.classList.remove('is-active'); + modalButton.focus(); + } + + function handleFocusTrap(event) { + const focusableEls = event.currentTarget.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'); + const firstFocusableEl = focusableEls[0]; + const lastFocusableEl = focusableEls[focusableEls.length - 1]; + + if (event.key !== 'Tab') { + return; + } + + if (event.shiftKey ) /* shift + tab */ { + if (document.activeElement === firstFocusableEl) { + lastFocusableEl.focus(); + event.preventDefault(); + } + } else /* tab */ { + if (document.activeElement === lastFocusableEl) { + firstFocusableEl.focus(); + event.preventDefault(); + } + } + } + + const modal = document.getElementById(targetModalId); + if (modal) { + // Open the modal + handleModalOpen(modal); + } + } + }(); diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index f2d04f96..4a7457dc 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -158,28 +158,14 @@ {% endwith %} - {% else %} + {% endif %} + + {% if not request.user.is_authenticated %} @@ -258,6 +244,51 @@ +{# Login modal #} +{% if not request.user.is_authenticated %} + +{% endif %} + From 89bbf005c39009bd9285cb87a671109de4150daa Mon Sep 17 00:00:00 2001 From: Joachim Date: Sat, 27 Nov 2021 19:19:09 +0100 Subject: [PATCH 009/256] Add an accessibility helper This will display a default outline specifically for keyboard users (and some inputs) --- bookwyrm/static/css/bookwyrm.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 81f0cf1a..333ddf80 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -8,6 +8,11 @@ body { flex-direction: column; } +/* Better accessibility for keyboard users */ +*:focus-visible { + outline-style: auto !important; +} + .image { overflow: hidden; } From c924f578e5b1555d32ceebfa7aff3fc615578d4d Mon Sep 17 00:00:00 2001 From: Joachim Date: Sun, 28 Nov 2021 18:26:01 +0100 Subject: [PATCH 010/256] Fix linting errors --- bookwyrm/static/css/bookwyrm.css | 4 ++++ bookwyrm/static/js/bookwyrm.js | 12 +++++++++++- bookwyrm/templates/layout.html | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 333ddf80..6a2eae34 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -30,15 +30,19 @@ body { overflow-x: auto; } +/* stylelint-disable no-descending-specificity */ .modal-card:focus { outline-style: auto; } + .modal-card:focus:not(:focus-visible) { outline-style: initial; } + .modal-card:focus-visible { outline-style: auto; } +/* stylelint-disable no-descending-specificity */ .modal-card.is-fullwidth { min-width: 75% !important; diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 5f062f78..8c2f107b 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -414,7 +414,17 @@ let BookWyrm = new class { } function handleFocusTrap(event) { - const focusableEls = event.currentTarget.querySelectorAll('a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'); + const focusableEls = event.currentTarget.querySelectorAll( + [ + 'a[href]:not([disabled])', + 'button:not([disabled])', + 'textarea:not([disabled])', + 'input[type="text"]:not([disabled])', + 'input[type="radio"]:not([disabled])', + 'input[type="checkbox"]:not([disabled])', + 'select:not([disabled])' + ].join(',') + ); const firstFocusableEl = focusableEls[0]; const lastFocusableEl = focusableEls[focusableEls.length - 1]; diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 4a7457dc..7296f136 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -285,7 +285,7 @@ - {% endif %} From a688c73b79942cbef9fdabfa0faa42b92cee3c81 Mon Sep 17 00:00:00 2001 From: Joachim Date: Sun, 28 Nov 2021 18:28:49 +0100 Subject: [PATCH 011/256] Fix stylelint rule --- bookwyrm/static/css/bookwyrm.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 6a2eae34..0b2f98ba 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -42,7 +42,7 @@ body { .modal-card:focus-visible { outline-style: auto; } -/* stylelint-disable no-descending-specificity */ +/* stylelint-enable no-descending-specificity */ .modal-card.is-fullwidth { min-width: 75% !important; From 3816b0aa5729a4367559e793ff25b6c8a237ab77 Mon Sep 17 00:00:00 2001 From: Joachim Date: Sun, 28 Nov 2021 18:34:54 +0100 Subject: [PATCH 012/256] Better JS --- bookwyrm/static/js/bookwyrm.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 8c2f107b..203d73d7 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -379,6 +379,11 @@ let BookWyrm = new class { const modalButton = element.currentTarget; const targetModalId = modalButton.dataset.modalOpen; const htmlElement = document.querySelector('html'); + const modal = document.getElementById(targetModalId); + + if (!modal) { + return; + } // Helper functions function handleModalOpen(modalElement) { @@ -387,10 +392,11 @@ let BookWyrm = new class { modalElement.getElementsByClassName('modal-card')[0].focus(); const closeButtons = modalElement.querySelectorAll("[data-modal-close]"); + closeButtons.forEach((button) => { button.addEventListener( - 'click', - function() { handleModalClose(modalElement) }, + 'click', + function() { handleModalClose(modalElement) } ); }); @@ -400,7 +406,7 @@ let BookWyrm = new class { if (event.key === 'Escape') { handleModalClose(modalElement); } - }, + } ); modalElement.addEventListener('keydown', handleFocusTrap) @@ -432,24 +438,20 @@ let BookWyrm = new class { return; } - if (event.shiftKey ) /* shift + tab */ { + if (event.shiftKey ) /* Shift + tab */ { if (document.activeElement === firstFocusableEl) { lastFocusableEl.focus(); event.preventDefault(); } - } else /* tab */ { + } else /* Tab */ { if (document.activeElement === lastFocusableEl) { firstFocusableEl.focus(); event.preventDefault(); } } } - - const modal = document.getElementById(targetModalId); - if (modal) { - // Open the modal - handleModalOpen(modal); - } + + // Open modal + handleModalOpen(modal); } - }(); From bf5cb898ef30dc11ce979bd0a77816af7f0a322c Mon Sep 17 00:00:00 2001 From: Joachim Date: Sun, 28 Nov 2021 21:45:35 +0100 Subject: [PATCH 013/256] Apply review suggestion --- bookwyrm/static/js/bookwyrm.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 203d73d7..868a75f4 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -425,10 +425,10 @@ let BookWyrm = new class { 'a[href]:not([disabled])', 'button:not([disabled])', 'textarea:not([disabled])', - 'input[type="text"]:not([disabled])', - 'input[type="radio"]:not([disabled])', - 'input[type="checkbox"]:not([disabled])', - 'select:not([disabled])' + 'input:not([type="hidden"]):not([disabled])', + 'select:not([disabled])', + 'details:not([disabled])', + '[tabindex]:not([tabindex="-1"]):not([disabled])' ].join(',') ); const firstFocusableEl = focusableEls[0]; From 9ec4ad6b319334bbb6bd647987421c37487afcb6 Mon Sep 17 00:00:00 2001 From: Joachim Date: Sun, 28 Nov 2021 21:46:32 +0100 Subject: [PATCH 014/256] Apply review suggestion --- bookwyrm/static/js/bookwyrm.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 868a75f4..4a2f882c 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -420,6 +420,10 @@ let BookWyrm = new class { } function handleFocusTrap(event) { + if (event.key !== 'Tab') { + return; + } + const focusableEls = event.currentTarget.querySelectorAll( [ 'a[href]:not([disabled])', @@ -434,10 +438,6 @@ let BookWyrm = new class { const firstFocusableEl = focusableEls[0]; const lastFocusableEl = focusableEls[focusableEls.length - 1]; - if (event.key !== 'Tab') { - return; - } - if (event.shiftKey ) /* Shift + tab */ { if (document.activeElement === firstFocusableEl) { lastFocusableEl.focus(); From 84b5c2da4eec9eaace8a1bc4bc0ae69c8799feef Mon Sep 17 00:00:00 2001 From: Joachim Date: Sun, 28 Nov 2021 22:10:15 +0100 Subject: [PATCH 015/256] Documentation --- bookwyrm/static/js/bookwyrm.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 4a2f882c..352bb7c7 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -375,8 +375,16 @@ let BookWyrm = new class { } } - handleModalButton(element) { - const modalButton = element.currentTarget; + /** + * Handle the modal component. + * + * @param {Event} event - Event fired by an element + * with the `data-modal-open` attribute + * pointing to a modal by its id. + * @return {undefined} + */ + handleModalButton(event) { + const modalButton = event.currentTarget; const targetModalId = modalButton.dataset.modalOpen; const htmlElement = document.querySelector('html'); const modal = document.getElementById(targetModalId); From eb4a39947252e8d97f9812daae15cde52562e97a Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 12:42:07 -0800 Subject: [PATCH 016/256] Updates models tests --- bookwyrm/lists_stream.py | 10 ++--- .../tests/models/test_activitypub_mixin.py | 8 ++-- bookwyrm/tests/models/test_base_model.py | 2 +- bookwyrm/tests/models/test_fields.py | 1 + bookwyrm/tests/models/test_group.py | 19 ++++---- bookwyrm/tests/models/test_import_model.py | 2 +- bookwyrm/tests/models/test_list.py | 6 +-- .../tests/models/test_readthrough_model.py | 2 +- .../tests/models/test_relationship_models.py | 45 +++++++++++++++---- bookwyrm/tests/models/test_shelf_model.py | 5 ++- bookwyrm/tests/models/test_site.py | 2 +- bookwyrm/tests/models/test_status_model.py | 2 +- bookwyrm/tests/models/test_user_model.py | 2 +- 13 files changed, 68 insertions(+), 38 deletions(-) diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py index 04a0725c..da8cdb21 100644 --- a/bookwyrm/lists_stream.py +++ b/bookwyrm/lists_stream.py @@ -9,7 +9,7 @@ from bookwyrm.tasks import app, MEDIUM, HIGH class ListsStream(RedisStore): - """a category of activity stream (like home, local, books)""" + """all the lists you can see""" def stream_id(self, user): # pylint: disable=no-self-use """the redis key for this user's instance of this stream""" @@ -122,9 +122,7 @@ def add_lists_on_follow(sender, instance, created, *args, **kwargs): """add a newly followed user's lists to feeds""" if not created or not instance.user_subject.local: return - add_user_lists_task.delay( - instance.user_subject.id, instance.user_object.id, stream_list=["home"] - ) + add_user_lists_task.delay(instance.user_subject.id, instance.user_object.id) @receiver(signals.post_delete, sender=models.UserFollows) @@ -133,9 +131,7 @@ def remove_lists_on_unfollow(sender, instance, *args, **kwargs): """remove lists from a feed on unfollow""" if not instance.user_subject.local: return - remove_user_lists_task.delay( - instance.user_subject.id, instance.user_object.id, stream_list=["home"] - ) + remove_user_lists_task.delay(instance.user_subject.id, instance.user_object.id) @receiver(signals.post_save, sender=models.UserBlocks) diff --git a/bookwyrm/tests/models/test_activitypub_mixin.py b/bookwyrm/tests/models/test_activitypub_mixin.py index 91a1fe7c..f1279ddf 100644 --- a/bookwyrm/tests/models/test_activitypub_mixin.py +++ b/bookwyrm/tests/models/test_activitypub_mixin.py @@ -29,7 +29,7 @@ class ActivitypubMixins(TestCase): """shared data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) @@ -332,7 +332,7 @@ class ActivitypubMixins(TestCase): self.assertEqual(activity["id"], "https://example.com/status/1/activity") self.assertEqual(activity["actor"], self.local_user.remote_id) self.assertEqual(activity["type"], "Delete") - self.assertEqual(activity["to"], ["%s/followers" % self.local_user.remote_id]) + self.assertEqual(activity["to"], [f"{self.local_user.remote_id}/followers"]) self.assertEqual( activity["cc"], ["https://www.w3.org/ns/activitystreams#Public"] ) @@ -374,7 +374,7 @@ class ActivitypubMixins(TestCase): for number in range(0, 2 * PAGE_LENGTH): models.Status.objects.create( user=self.local_user, - content="test status {:d}".format(number), + content=f"test status {number}", ) page_1 = to_ordered_collection_page( models.Status.objects.all(), "http://fish.com/", page=1 @@ -400,7 +400,7 @@ class ActivitypubMixins(TestCase): for number in range(0, 2 * PAGE_LENGTH): models.Status.objects.create( user=self.local_user, - content="test status {:d}".format(number), + content=f"test status {number}", ) MockSelf = namedtuple("Self", ("remote_id")) diff --git a/bookwyrm/tests/models/test_base_model.py b/bookwyrm/tests/models/test_base_model.py index 7c7b48de..ae6d1207 100644 --- a/bookwyrm/tests/models/test_base_model.py +++ b/bookwyrm/tests/models/test_base_model.py @@ -16,7 +16,7 @@ class BaseModel(TestCase): """shared data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_fields.py b/bookwyrm/tests/models/test_fields.py index 8028a305..c3402a25 100644 --- a/bookwyrm/tests/models/test_fields.py +++ b/bookwyrm/tests/models/test_fields.py @@ -27,6 +27,7 @@ from bookwyrm.settings import DOMAIN # pylint: disable=too-many-public-methods @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") class ModelFields(TestCase): """overwrites standard model feilds to work with activitypub""" diff --git a/bookwyrm/tests/models/test_group.py b/bookwyrm/tests/models/test_group.py index 2dd3cee1..3439a1bf 100644 --- a/bookwyrm/tests/models/test_group.py +++ b/bookwyrm/tests/models/test_group.py @@ -2,7 +2,7 @@ from unittest.mock import patch from django.test import TestCase -from bookwyrm import models, settings +from bookwyrm import models @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @@ -14,21 +14,21 @@ class Group(TestCase): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.owner_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.rat = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", local=True, localname="rat" ) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.badger = models.User.objects.create_user( "badger", "badger@badger.badger", @@ -39,7 +39,7 @@ class Group(TestCase): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.capybara = models.User.objects.create_user( "capybara", "capybara@capybara.capybara", @@ -76,7 +76,8 @@ class Group(TestCase): models.GroupMember.objects.create(group=self.public_group, user=self.capybara) def test_group_members_can_see_private_groups(self, _): - """direct privacy group should not be excluded from group listings for group members viewing""" + """direct privacy group should not be excluded from group listings for group + members viewing""" rat_groups = models.Group.privacy_filter(self.rat).all() badger_groups = models.Group.privacy_filter(self.badger).all() @@ -85,7 +86,8 @@ class Group(TestCase): self.assertTrue(self.private_group in badger_groups) def test_group_members_can_see_followers_only_lists(self, _): - """follower-only group booklists should not be excluded from group booklist listing for group members who do not follower list owner""" + """follower-only group booklists should not be excluded from group booklist + listing for group members who do not follower list owner""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): followers_list = models.List.objects.create( @@ -105,7 +107,8 @@ class Group(TestCase): self.assertTrue(followers_list in capybara_lists) def test_group_members_can_see_private_lists(self, _): - """private group booklists should not be excluded from group booklist listing for group members""" + """private group booklists should not be excluded from group booklist listing + for group members""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): diff --git a/bookwyrm/tests/models/test_import_model.py b/bookwyrm/tests/models/test_import_model.py index f48143d0..225466f3 100644 --- a/bookwyrm/tests/models/test_import_model.py +++ b/bookwyrm/tests/models/test_import_model.py @@ -20,7 +20,7 @@ class ImportJob(TestCase): """data is from a goodreads export of The Raven Tower""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/models/test_list.py b/bookwyrm/tests/models/test_list.py index 824de835..e4ecfe89 100644 --- a/bookwyrm/tests/models/test_list.py +++ b/bookwyrm/tests/models/test_list.py @@ -1,7 +1,7 @@ """ testing models """ +from uuid import UUID from unittest.mock import patch from django.test import TestCase -from uuid import UUID from bookwyrm import models, settings @@ -14,7 +14,7 @@ class List(TestCase): """look, a list""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) @@ -27,7 +27,7 @@ class List(TestCase): book_list = models.List.objects.create( name="Test List", user=self.local_user ) - expected_id = "https://%s/list/%d" % (settings.DOMAIN, book_list.id) + expected_id = f"https://{settings.DOMAIN}/list/{book_list.id}" self.assertEqual(book_list.get_remote_id(), expected_id) def test_to_activity(self, _): diff --git a/bookwyrm/tests/models/test_readthrough_model.py b/bookwyrm/tests/models/test_readthrough_model.py index 5d8450a1..7e3963cf 100644 --- a/bookwyrm/tests/models/test_readthrough_model.py +++ b/bookwyrm/tests/models/test_readthrough_model.py @@ -15,7 +15,7 @@ class ReadThrough(TestCase): """look, a shelf""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_relationship_models.py b/bookwyrm/tests/models/test_relationship_models.py index 2b388398..a5b4dbff 100644 --- a/bookwyrm/tests/models/test_relationship_models.py +++ b/bookwyrm/tests/models/test_relationship_models.py @@ -1,12 +1,16 @@ """ testing models """ import json from unittest.mock import patch +from django.db import IntegrityError from django.test import TestCase from bookwyrm import models @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") +@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") +@patch("bookwyrm.lists_stream.add_user_lists_task.delay") +@patch("bookwyrm.lists_stream.remove_user_lists_task.delay") class Relationship(TestCase): """following, blocking, stuff like that""" @@ -24,14 +28,39 @@ class Relationship(TestCase): ) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse" ) self.local_user.remote_id = "http://local.com/user/mouse" self.local_user.save(broadcast=False, update_fields=["remote_id"]) - def test_user_follows_from_request(self, _): + def test_user_follows(self, *_): + """basic functionality of user follows""" + relationship = models.UserFollows.objects.create( + user_subject=self.local_user, user_object=self.remote_user + ) + self.assertEqual(relationship.status, "follows") + activity = relationship.to_activity() + self.assertEqual(activity.type, "Follow") + self.assertEqual( + relationship.remote_id, + f"http://local.com/user/mouse#follows/{relationship.id}", + ) + + def test_user_follows_blocks(self, *_): + """can't follow if you're blocked""" + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + models.UserBlocks.objects.create( + user_subject=self.local_user, user_object=self.remote_user + ) + + with self.assertRaises(IntegrityError): + models.UserFollows.objects.create( + user_subject=self.local_user, user_object=self.remote_user + ) + + def test_user_follows_from_request(self, *_): """convert a follow request into a follow""" with patch( "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" @@ -42,19 +71,19 @@ class Relationship(TestCase): activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Follow") self.assertEqual( - request.remote_id, "http://local.com/user/mouse#follows/%d" % request.id + request.remote_id, f"http://local.com/user/mouse#follows/{request.id}" ) self.assertEqual(request.status, "follow_request") rel = models.UserFollows.from_request(request) self.assertEqual( - rel.remote_id, "http://local.com/user/mouse#follows/%d" % request.id + rel.remote_id, f"http://local.com/user/mouse#follows/{request.id}" ) self.assertEqual(rel.status, "follows") self.assertEqual(rel.user_subject, self.local_user) self.assertEqual(rel.user_object, self.remote_user) - def test_user_follows_from_request_custom_remote_id(self, _): + def test_user_follows_from_request_custom_remote_id(self, *_): """store a specific remote id for a relationship provided by remote""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): request = models.UserFollowRequest.objects.create( @@ -72,7 +101,7 @@ class Relationship(TestCase): self.assertEqual(rel.user_object, self.remote_user) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_follow_request_activity(self, broadcast_mock, _): + def test_follow_request_activity(self, broadcast_mock, *_): """accept a request and make it a relationship""" models.UserFollowRequest.objects.create( user_subject=self.local_user, @@ -84,7 +113,7 @@ class Relationship(TestCase): self.assertEqual(activity["type"], "Follow") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_follow_request_accept(self, broadcast_mock, _): + def test_follow_request_accept(self, broadcast_mock, *_): """accept a request and make it a relationship""" self.local_user.manually_approves_followers = True self.local_user.save( @@ -110,7 +139,7 @@ class Relationship(TestCase): self.assertEqual(rel.user_object, self.local_user) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") - def test_follow_request_reject(self, broadcast_mock, _): + def test_follow_request_reject(self, broadcast_mock, *_): """accept a request and make it a relationship""" self.local_user.manually_approves_followers = True self.local_user.save( diff --git a/bookwyrm/tests/models/test_shelf_model.py b/bookwyrm/tests/models/test_shelf_model.py index 0683fbef..4f7f3589 100644 --- a/bookwyrm/tests/models/test_shelf_model.py +++ b/bookwyrm/tests/models/test_shelf_model.py @@ -9,6 +9,7 @@ from bookwyrm import models, settings # pylint: disable=unused-argument @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class Shelf(TestCase): @@ -18,7 +19,7 @@ class Shelf(TestCase): """look, a shelf""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) @@ -31,7 +32,7 @@ class Shelf(TestCase): shelf = models.Shelf.objects.create( name="Test Shelf", identifier="test-shelf", user=self.local_user ) - expected_id = "https://%s/user/mouse/books/test-shelf" % settings.DOMAIN + expected_id = f"https://{settings.DOMAIN}/user/mouse/books/test-shelf" self.assertEqual(shelf.get_remote_id(), expected_id) def test_to_activity(self, *_): diff --git a/bookwyrm/tests/models/test_site.py b/bookwyrm/tests/models/test_site.py index b7c19c4b..d23f7988 100644 --- a/bookwyrm/tests/models/test_site.py +++ b/bookwyrm/tests/models/test_site.py @@ -16,7 +16,7 @@ class SiteModels(TestCase): """we need basic test data and mocks""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/models/test_status_model.py b/bookwyrm/tests/models/test_status_model.py index 822d837a..6520094c 100644 --- a/bookwyrm/tests/models/test_status_model.py +++ b/bookwyrm/tests/models/test_status_model.py @@ -28,7 +28,7 @@ class Status(TestCase): """useful things for creating a status""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/models/test_user_model.py b/bookwyrm/tests/models/test_user_model.py index 389928cd..aa62dce3 100644 --- a/bookwyrm/tests/models/test_user_model.py +++ b/bookwyrm/tests/models/test_user_model.py @@ -15,7 +15,7 @@ class User(TestCase): def setUp(self): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse@%s" % DOMAIN, "mouse@mouse.mouse", From 7a89552892703648cff1fa6616a3f52dcec9b64e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 13:01:50 -0800 Subject: [PATCH 017/256] Updates test_* tests --- bookwyrm/tests/test_emailing.py | 2 +- bookwyrm/tests/test_preview_images.py | 2 +- bookwyrm/tests/test_signing.py | 10 +++++----- bookwyrm/tests/test_suggested_users.py | 3 ++- bookwyrm/tests/test_templatetags.py | 19 +++++++++++++------ 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/bookwyrm/tests/test_emailing.py b/bookwyrm/tests/test_emailing.py index 2f24122e..ecfbd944 100644 --- a/bookwyrm/tests/test_emailing.py +++ b/bookwyrm/tests/test_emailing.py @@ -16,7 +16,7 @@ class Emailing(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/test_preview_images.py b/bookwyrm/tests/test_preview_images.py index f95e623c..79ee195d 100644 --- a/bookwyrm/tests/test_preview_images.py +++ b/bookwyrm/tests/test_preview_images.py @@ -32,7 +32,7 @@ class PreviewImages(TestCase): ) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "possum@local.com", "possum@possum.possum", diff --git a/bookwyrm/tests/test_signing.py b/bookwyrm/tests/test_signing.py index d33687a5..da67a8de 100644 --- a/bookwyrm/tests/test_signing.py +++ b/bookwyrm/tests/test_signing.py @@ -39,19 +39,19 @@ class Signature(TestCase): """create users and test data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.mouse = models.User.objects.create_user( - "mouse@%s" % DOMAIN, + f"mouse@{DOMAIN}", "mouse@example.com", "", local=True, localname="mouse", ) self.rat = models.User.objects.create_user( - "rat@%s" % DOMAIN, "rat@example.com", "", local=True, localname="rat" + f"rat@{DOMAIN}", "rat@example.com", "", local=True, localname="rat" ) self.cat = models.User.objects.create_user( - "cat@%s" % DOMAIN, "cat@example.com", "", local=True, localname="cat" + f"cat@{DOMAIN}", "cat@example.com", "", local=True, localname="cat" ) private_key, public_key = create_key_pair() @@ -75,7 +75,7 @@ class Signature(TestCase): "HTTP_DIGEST": digest, "HTTP_CONTENT_TYPE": "application/activity+json; charset=utf-8", "HTTP_HOST": DOMAIN, - } + }, ) def send_test_request( # pylint: disable=too-many-arguments diff --git a/bookwyrm/tests/test_suggested_users.py b/bookwyrm/tests/test_suggested_users.py index dce5d770..91677f19 100644 --- a/bookwyrm/tests/test_suggested_users.py +++ b/bookwyrm/tests/test_suggested_users.py @@ -13,6 +13,7 @@ from bookwyrm.suggested_users import suggested_users, get_annotated_users @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") @@ -23,7 +24,7 @@ class SuggestedUsers(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/test_templatetags.py b/bookwyrm/tests/test_templatetags.py index ed4466f5..b7b1d748 100644 --- a/bookwyrm/tests/test_templatetags.py +++ b/bookwyrm/tests/test_templatetags.py @@ -24,7 +24,7 @@ class TemplateTags(TestCase): """create some filler objects""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.mouse", @@ -42,6 +42,18 @@ class TemplateTags(TestCase): ) self.book = models.Edition.objects.create(title="Test Book") + def test_get_uuid(self, *_): + """uuid functionality""" + uuid = utilities.get_uuid("hi") + self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid)) + + def test_get_title(self, *_): + """the title of a book""" + self.assertEqual(utilities.get_title(None), "") + self.assertEqual(utilities.get_title(self.book), "Test Book") + book = models.Edition.objects.create(title="Oh", subtitle="oh my") + self.assertEqual(utilities.get_title(book), "Oh: oh my") + def test_get_user_rating(self, *_): """get a user's most recent rating of a book""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): @@ -145,11 +157,6 @@ class TemplateTags(TestCase): self.book.save() self.assertEqual(bookwyrm_tags.get_book_description(self.book), "hello") - def test_get_uuid(self, *_): - """uuid functionality""" - uuid = utilities.get_uuid("hi") - self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid)) - def test_get_markdown(self, *_): """mardown format data""" result = markdown.get_markdown("_hi_") From 93dbe2daa0fd5ffc8d3f38749c423e9af1d0d09e Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 15:02:53 -0800 Subject: [PATCH 018/256] Updates inbox tests --- bookwyrm/tests/views/inbox/test_inbox.py | 2 +- bookwyrm/tests/views/inbox/test_inbox_add.py | 2 +- bookwyrm/tests/views/inbox/test_inbox_announce.py | 2 +- bookwyrm/tests/views/inbox/test_inbox_block.py | 8 +++++--- bookwyrm/tests/views/inbox/test_inbox_create.py | 2 +- bookwyrm/tests/views/inbox/test_inbox_delete.py | 10 ++++++---- bookwyrm/tests/views/inbox/test_inbox_follow.py | 5 +++-- bookwyrm/tests/views/inbox/test_inbox_like.py | 2 +- bookwyrm/tests/views/inbox/test_inbox_remove.py | 2 +- bookwyrm/tests/views/inbox/test_inbox_update.py | 3 ++- 10 files changed, 22 insertions(+), 16 deletions(-) diff --git a/bookwyrm/tests/views/inbox/test_inbox.py b/bookwyrm/tests/views/inbox/test_inbox.py index 47e6a86e..e328b1ba 100644 --- a/bookwyrm/tests/views/inbox/test_inbox.py +++ b/bookwyrm/tests/views/inbox/test_inbox.py @@ -22,7 +22,7 @@ class Inbox(TestCase): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_add.py b/bookwyrm/tests/views/inbox/test_inbox_add.py index 33e6c55b..a9a80982 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_add.py +++ b/bookwyrm/tests/views/inbox/test_inbox_add.py @@ -15,7 +15,7 @@ class InboxAdd(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_announce.py b/bookwyrm/tests/views/inbox/test_inbox_announce.py index a291552d..01580c92 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_announce.py +++ b/bookwyrm/tests/views/inbox/test_inbox_announce.py @@ -15,7 +15,7 @@ class InboxActivities(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_block.py b/bookwyrm/tests/views/inbox/test_inbox_block.py index f6898fc6..eb73af09 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_block.py +++ b/bookwyrm/tests/views/inbox/test_inbox_block.py @@ -14,7 +14,7 @@ class InboxBlock(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -57,7 +57,7 @@ class InboxBlock(TestCase): with patch( "bookwyrm.activitystreams.remove_user_statuses_task.delay" - ) as redis_mock: + ) as redis_mock, patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): views.inbox.activity_task(activity) self.assertTrue(redis_mock.called) views.inbox.activity_task(activity) @@ -70,7 +70,9 @@ class InboxBlock(TestCase): self.assertFalse(models.UserFollowRequest.objects.exists()) @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") - def test_handle_unblock(self, _): + @patch("bookwyrm.lists_stream.add_user_lists_task.delay") + @patch("bookwyrm.lists_stream.remove_user_lists_task.delay") + def test_handle_unblock(self, *_): """unblock a user""" self.remote_user.blocks.add(self.local_user) diff --git a/bookwyrm/tests/views/inbox/test_inbox_create.py b/bookwyrm/tests/views/inbox/test_inbox_create.py index 53b17d68..4ee366cf 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_create.py +++ b/bookwyrm/tests/views/inbox/test_inbox_create.py @@ -19,7 +19,7 @@ class InboxCreate(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_delete.py b/bookwyrm/tests/views/inbox/test_inbox_delete.py index dd603352..b4863aad 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_delete.py +++ b/bookwyrm/tests/views/inbox/test_inbox_delete.py @@ -15,7 +15,7 @@ class InboxActivities(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -51,7 +51,7 @@ class InboxActivities(TestCase): "type": "Delete", "to": ["https://www.w3.org/ns/activitystreams#Public"], "cc": ["https://example.com/user/mouse/followers"], - "id": "%s/activity" % self.status.remote_id, + "id": f"{self.status.remote_id}/activity", "actor": self.remote_user.remote_id, "object": {"id": self.status.remote_id, "type": "Tombstone"}, } @@ -80,7 +80,7 @@ class InboxActivities(TestCase): "type": "Delete", "to": ["https://www.w3.org/ns/activitystreams#Public"], "cc": ["https://example.com/user/mouse/followers"], - "id": "%s/activity" % self.status.remote_id, + "id": f"{self.status.remote_id}/activity", "actor": self.remote_user.remote_id, "object": {"id": self.status.remote_id, "type": "Tombstone"}, } @@ -152,5 +152,7 @@ class InboxActivities(TestCase): "cc": [], }, } - views.inbox.activity_task(activity) + with patch("bookwyrm.lists_stream.remove_list_task.delay") as mock: + views.inbox.activity_task(activity) + self.assertTrue(mock.called) self.assertFalse(models.List.objects.exists()) diff --git a/bookwyrm/tests/views/inbox/test_inbox_follow.py b/bookwyrm/tests/views/inbox/test_inbox_follow.py index 71f101ca..13e46ff8 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_follow.py +++ b/bookwyrm/tests/views/inbox/test_inbox_follow.py @@ -15,7 +15,7 @@ class InboxRelationships(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -188,7 +188,8 @@ class InboxRelationships(TestCase): self.assertIsNone(self.local_user.followers.first()) @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") - def test_follow_accept(self, _): + @patch("bookwyrm.lists_stream.add_user_lists_task.delay") + def test_follow_accept(self, *_): """a remote user approved a follow request from local""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): rel = models.UserFollowRequest.objects.create( diff --git a/bookwyrm/tests/views/inbox/test_inbox_like.py b/bookwyrm/tests/views/inbox/test_inbox_like.py index 2f1b6629..ea4d4a65 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_like.py +++ b/bookwyrm/tests/views/inbox/test_inbox_like.py @@ -14,7 +14,7 @@ class InboxActivities(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_remove.py b/bookwyrm/tests/views/inbox/test_inbox_remove.py index 55cc8120..53288e0d 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_remove.py +++ b/bookwyrm/tests/views/inbox/test_inbox_remove.py @@ -14,7 +14,7 @@ class InboxRemove(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/inbox/test_inbox_update.py b/bookwyrm/tests/views/inbox/test_inbox_update.py index 248c1ad2..052b47c4 100644 --- a/bookwyrm/tests/views/inbox/test_inbox_update.py +++ b/bookwyrm/tests/views/inbox/test_inbox_update.py @@ -16,7 +16,7 @@ class InboxUpdate(TestCase): """basic user and book data""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@example.com", "mouse@mouse.com", @@ -78,6 +78,7 @@ class InboxUpdate(TestCase): @patch("bookwyrm.suggested_users.rerank_user_task.delay") @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + @patch("bookwyrm.lists_stream.add_user_lists_task.delay") def test_update_user(self, *_): """update an existing user""" models.UserFollows.objects.create( From 2d63bfb791cd13ff38c30dc9b3886e4903c52d76 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 15:03:01 -0800 Subject: [PATCH 019/256] Updates views tests --- bookwyrm/tests/views/test_author.py | 2 +- bookwyrm/tests/views/test_directory.py | 3 ++- bookwyrm/tests/views/test_discover.py | 7 +++--- bookwyrm/tests/views/test_feed.py | 25 ++++++++++++++++++--- bookwyrm/tests/views/test_follow.py | 26 ++++++++++++---------- bookwyrm/tests/views/test_get_started.py | 2 +- bookwyrm/tests/views/test_goal.py | 2 +- bookwyrm/tests/views/test_group.py | 2 +- bookwyrm/tests/views/test_helpers.py | 2 +- bookwyrm/tests/views/test_interaction.py | 2 +- bookwyrm/tests/views/test_isbn.py | 12 +++++++++- bookwyrm/tests/views/test_list.py | 24 ++++++++++++-------- bookwyrm/tests/views/test_list_actions.py | 10 ++++----- bookwyrm/tests/views/test_notifications.py | 2 +- bookwyrm/tests/views/test_outbox.py | 2 +- bookwyrm/tests/views/test_reading.py | 2 +- bookwyrm/tests/views/test_readthrough.py | 2 +- bookwyrm/tests/views/test_rss_feed.py | 2 +- bookwyrm/tests/views/test_search.py | 2 +- bookwyrm/tests/views/test_status.py | 3 ++- bookwyrm/tests/views/test_updates.py | 2 +- bookwyrm/tests/views/test_user.py | 2 +- bookwyrm/tests/views/test_wellknown.py | 2 +- bookwyrm/views/feed.py | 4 +++- 24 files changed, 92 insertions(+), 52 deletions(-) diff --git a/bookwyrm/tests/views/test_author.py b/bookwyrm/tests/views/test_author.py index 03166932..ad5c069d 100644 --- a/bookwyrm/tests/views/test_author.py +++ b/bookwyrm/tests/views/test_author.py @@ -21,7 +21,7 @@ class AuthorViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_directory.py b/bookwyrm/tests/views/test_directory.py index 4fe2aa05..bceb0e7a 100644 --- a/bookwyrm/tests/views/test_directory.py +++ b/bookwyrm/tests/views/test_directory.py @@ -18,7 +18,7 @@ class DirectoryViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -34,6 +34,7 @@ class DirectoryViews(TestCase): @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") + @patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.suggested_users.rerank_user_task.delay") def test_directory_page(self, *_): """there are so many views, this just makes sure it LOADS""" diff --git a/bookwyrm/tests/views/test_discover.py b/bookwyrm/tests/views/test_discover.py index b2a82241..bff420c8 100644 --- a/bookwyrm/tests/views/test_discover.py +++ b/bookwyrm/tests/views/test_discover.py @@ -6,6 +6,7 @@ from django.test.client import RequestFactory from bookwyrm import models from bookwyrm import views +from bookwyrm.tests.validate_html import validate_html class DiscoverViews(TestCase): @@ -16,7 +17,7 @@ class DiscoverViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -39,7 +40,7 @@ class DiscoverViews(TestCase): result = view(request) self.assertEqual(mock.call_count, 1) self.assertEqual(result.status_code, 200) - result.render() + validate_html(result.render()) @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.activitystreams.add_status_task.delay") @@ -67,7 +68,7 @@ class DiscoverViews(TestCase): result = view(request) self.assertEqual(mock.call_count, 1) self.assertEqual(result.status_code, 200) - result.render() + validate_html(result.render()) def test_discover_page_logged_out(self): """there are so many views, this just makes sure it LOADS""" diff --git a/bookwyrm/tests/views/test_feed.py b/bookwyrm/tests/views/test_feed.py index 5c6a4dd3..7f8db948 100644 --- a/bookwyrm/tests/views/test_feed.py +++ b/bookwyrm/tests/views/test_feed.py @@ -10,8 +10,7 @@ from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory -from bookwyrm import models -from bookwyrm import views +from bookwyrm import forms, models, views from bookwyrm.activitypub import ActivitypubResponse @@ -19,6 +18,7 @@ from bookwyrm.activitypub import ActivitypubResponse @patch("bookwyrm.activitystreams.add_status_task.delay") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.suggested_users.remove_user_task.delay") class FeedViews(TestCase): """activity feed, statuses, dms""" @@ -28,7 +28,7 @@ class FeedViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -54,6 +54,25 @@ class FeedViews(TestCase): result.render() self.assertEqual(result.status_code, 200) + @patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions") + def test_save_feed_settings(self, *_): + """update display preferences""" + self.assertEqual( + self.local_user.feed_status_types, + ["review", "comment", "quotation", "everything"], + ) + view = views.Feed.as_view() + form = forms.FeedStatusTypesForm(instance=self.local_user) + form.data["feed_status_types"] = "review" + request = self.factory.post("", form.data) + request.user = self.local_user + + result = view(request, "home") + + self.assertEqual(result.status_code, 200) + self.local_user.refresh_from_db() + self.assertEqual(self.local_user.feed_status_types, ["review"]) + def test_status_page(self, *_): """there are so many views, this just makes sure it LOADS""" view = views.Status.as_view() diff --git a/bookwyrm/tests/views/test_follow.py b/bookwyrm/tests/views/test_follow.py index 046fe3d9..d18e24f8 100644 --- a/bookwyrm/tests/views/test_follow.py +++ b/bookwyrm/tests/views/test_follow.py @@ -13,6 +13,7 @@ from bookwyrm.tests.validate_html import validate_html @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") +@patch("bookwyrm.lists_stream.add_user_lists_task.delay") class FollowViews(TestCase): """follows""" @@ -22,7 +23,7 @@ class FollowViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -56,7 +57,7 @@ class FollowViews(TestCase): parent_work=self.work, ) - def test_handle_follow_remote(self, _): + def test_handle_follow_remote(self, *_): """send a follow request""" request = self.factory.post("", {"user": self.remote_user.username}) request.user = self.local_user @@ -71,11 +72,11 @@ class FollowViews(TestCase): self.assertEqual(rel.user_object, self.remote_user) self.assertEqual(rel.status, "follow_request") - def test_handle_follow_local_manually_approves(self, _): + def test_handle_follow_local_manually_approves(self, *_): """send a follow request""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", @@ -97,11 +98,11 @@ class FollowViews(TestCase): self.assertEqual(rel.user_object, rat) self.assertEqual(rel.status, "follow_request") - def test_handle_follow_local(self, _): + def test_handle_follow_local(self, *_): """send a follow request""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): rat = models.User.objects.create_user( "rat@local.com", "rat@rat.com", @@ -124,6 +125,7 @@ class FollowViews(TestCase): self.assertEqual(rel.status, "follows") @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + @patch("bookwyrm.lists_stream.remove_user_lists_task.delay") def test_handle_unfollow(self, *_): """send an unfollow""" request = self.factory.post("", {"user": self.remote_user.username}) @@ -140,7 +142,7 @@ class FollowViews(TestCase): self.assertEqual(self.remote_user.followers.count(), 0) - def test_handle_accept(self, _): + def test_handle_accept(self, *_): """accept a follow request""" self.local_user.manually_approves_followers = True self.local_user.save( @@ -159,7 +161,7 @@ class FollowViews(TestCase): # follow relationship should exist self.assertEqual(self.local_user.followers.first(), self.remote_user) - def test_handle_reject(self, _): + def test_handle_reject(self, *_): """reject a follow request""" self.local_user.manually_approves_followers = True self.local_user.save( @@ -178,7 +180,7 @@ class FollowViews(TestCase): # follow relationship should not exist self.assertEqual(models.UserFollows.objects.filter(id=rel.id).count(), 0) - def test_ostatus_follow_request(self, _): + def test_ostatus_follow_request(self, *_): """check ostatus subscribe template loads""" request = self.factory.get( "", {"acct": "https%3A%2F%2Fexample.com%2Fusers%2Frat"} @@ -189,7 +191,7 @@ class FollowViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) - def test_remote_follow_page(self, _): + def test_remote_follow_page(self, *_): """check remote follow page loads""" request = self.factory.get("", {"acct": "mouse@local.com"}) request.user = self.remote_user @@ -198,7 +200,7 @@ class FollowViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) - def test_ostatus_follow_success(self, _): + def test_ostatus_follow_success(self, *_): """check remote follow success page loads""" request = self.factory.get("") request.user = self.remote_user @@ -208,7 +210,7 @@ class FollowViews(TestCase): validate_html(result.render()) self.assertEqual(result.status_code, 200) - def test_remote_follow(self, _): + def test_remote_follow(self, *_): """check follow from remote page loads""" request = self.factory.post("", {"user": self.remote_user.id}) request.user = self.remote_user diff --git a/bookwyrm/tests/views/test_get_started.py b/bookwyrm/tests/views/test_get_started.py index 6d1819a4..a54940e3 100644 --- a/bookwyrm/tests/views/test_get_started.py +++ b/bookwyrm/tests/views/test_get_started.py @@ -16,7 +16,7 @@ class GetStartedViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_goal.py b/bookwyrm/tests/views/test_goal.py index 73207240..0faeef11 100644 --- a/bookwyrm/tests/views/test_goal.py +++ b/bookwyrm/tests/views/test_goal.py @@ -20,7 +20,7 @@ class GoalViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_group.py b/bookwyrm/tests/views/test_group.py index b18ce6b4..87776dc5 100644 --- a/bookwyrm/tests/views/test_group.py +++ b/bookwyrm/tests/views/test_group.py @@ -19,7 +19,7 @@ class GroupViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_helpers.py b/bookwyrm/tests/views/test_helpers.py index 1aae830f..8fe04f51 100644 --- a/bookwyrm/tests/views/test_helpers.py +++ b/bookwyrm/tests/views/test_helpers.py @@ -23,7 +23,7 @@ class ViewsHelpers(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): with patch("bookwyrm.suggested_users.rerank_user_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", diff --git a/bookwyrm/tests/views/test_interaction.py b/bookwyrm/tests/views/test_interaction.py index aa402952..1d729f9a 100644 --- a/bookwyrm/tests/views/test_interaction.py +++ b/bookwyrm/tests/views/test_interaction.py @@ -17,7 +17,7 @@ class InteractionViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_isbn.py b/bookwyrm/tests/views/test_isbn.py index bdf72f75..7c18b4ab 100644 --- a/bookwyrm/tests/views/test_isbn.py +++ b/bookwyrm/tests/views/test_isbn.py @@ -18,7 +18,7 @@ class IsbnViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -49,3 +49,13 @@ class IsbnViews(TestCase): self.assertEqual(len(data), 1) self.assertEqual(data[0]["title"], "Test Book") self.assertEqual(data[0]["key"], f"https://{DOMAIN}/book/{self.book.id}") + + def test_isbn_html_response(self): + """searches local data only and returns book data in json format""" + view = views.Isbn.as_view() + request = self.factory.get("") + with patch("bookwyrm.views.isbn.is_api_request") as is_api: + is_api.return_value = False + response = view(request, isbn="1234567890123") + self.assertEqual(response.status_code, 200) + response.render() diff --git a/bookwyrm/tests/views/test_list.py b/bookwyrm/tests/views/test_list.py index fd4d2d76..aa942a39 100644 --- a/bookwyrm/tests/views/test_list.py +++ b/bookwyrm/tests/views/test_list.py @@ -20,7 +20,7 @@ class ListViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -71,10 +71,13 @@ class ListViews(TestCase): models.SiteSettings.objects.create() - def test_lists_page(self): + @patch("bookwyrm.lists_stream.ListsStream.get_activity_stream") + def test_lists_page(self, _): """there are so many views, this just makes sure it LOADS""" view = views.Lists.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + with patch( + "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" + ), patch("bookwyrm.lists_stream.add_list_task.delay"): models.List.objects.create(name="Public list", user=self.local_user) models.List.objects.create( name="Private list", privacy="direct", user=self.local_user @@ -345,13 +348,16 @@ class ListViews(TestCase): def test_curate_page(self): """there are so many views, this just makes sure it LOADS""" view = views.Curate.as_view() - with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): - models.List.objects.create(name="Public list", user=self.local_user) - models.List.objects.create( - name="Private list", privacy="direct", user=self.local_user - ) request = self.factory.get("") request.user = self.local_user + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + models.ListItem.objects.create( + book_list=self.list, + user=self.local_user, + book=self.book, + approved=False, + order=1, + ) result = view(request, self.list.id) self.assertIsInstance(result, TemplateResponse) @@ -404,7 +410,7 @@ class ListViews(TestCase): with patch("bookwyrm.views.list.is_api_request") as is_api: is_api.return_value = False with self.assertRaises(Http404): - result = view(request, self.list.id, "") + view(request, self.list.id, "") def test_embed_call_with_key(self): """there are so many views, this just makes sure it LOADS""" diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index 1d9f46b3..0d04a8f2 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -18,7 +18,7 @@ class ListActionViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -90,8 +90,9 @@ class ListActionViews(TestCase): request.user = self.local_user with patch( "bookwyrm.models.activitypub_mixin.broadcast_task.apply_async" - ) as mock: + ) as mock, patch("bookwyrm.lists_stream.remove_list_task.delay") as redis_mock: views.delete_list(request, self.list.id) + self.assertTrue(redis_mock.called) activity = json.loads(mock.call_args[1]["args"][1]) self.assertEqual(activity["type"], "Delete") self.assertEqual(activity["actor"], self.local_user.remote_id) @@ -123,10 +124,7 @@ class ListActionViews(TestCase): request = self.factory.post( "", - { - "item": pending.id, - "approved": "true", - }, + {"item": pending.id, "approved": "true"}, ) request.user = self.local_user diff --git a/bookwyrm/tests/views/test_notifications.py b/bookwyrm/tests/views/test_notifications.py index 5df62b1d..2a5cf798 100644 --- a/bookwyrm/tests/views/test_notifications.py +++ b/bookwyrm/tests/views/test_notifications.py @@ -17,7 +17,7 @@ class NotificationViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_outbox.py b/bookwyrm/tests/views/test_outbox.py index 5c5d47b0..598cce51 100644 --- a/bookwyrm/tests/views/test_outbox.py +++ b/bookwyrm/tests/views/test_outbox.py @@ -20,7 +20,7 @@ class OutboxView(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_reading.py b/bookwyrm/tests/views/test_reading.py index 4ec50165..0d6c13aa 100644 --- a/bookwyrm/tests/views/test_reading.py +++ b/bookwyrm/tests/views/test_reading.py @@ -20,7 +20,7 @@ class ReadingViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_readthrough.py b/bookwyrm/tests/views/test_readthrough.py index 5b554748..6697c0e0 100644 --- a/bookwyrm/tests/views/test_readthrough.py +++ b/bookwyrm/tests/views/test_readthrough.py @@ -27,7 +27,7 @@ class ReadThrough(TestCase): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "cinco", "cinco@example.com", "seissiete", local=True, localname="cinco" ) diff --git a/bookwyrm/tests/views/test_rss_feed.py b/bookwyrm/tests/views/test_rss_feed.py index 409c306d..8b3ecf58 100644 --- a/bookwyrm/tests/views/test_rss_feed.py +++ b/bookwyrm/tests/views/test_rss_feed.py @@ -15,7 +15,7 @@ class RssFeedView(TestCase): def setUp(self): with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "rss_user", "rss@test.rss", "password", local=True ) diff --git a/bookwyrm/tests/views/test_search.py b/bookwyrm/tests/views/test_search.py index f8045511..a7822f1c 100644 --- a/bookwyrm/tests/views/test_search.py +++ b/bookwyrm/tests/views/test_search.py @@ -22,7 +22,7 @@ class Views(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_status.py b/bookwyrm/tests/views/test_status.py index b5d7ac16..35507157 100644 --- a/bookwyrm/tests/views/test_status.py +++ b/bookwyrm/tests/views/test_status.py @@ -13,6 +13,7 @@ from bookwyrm.tests.validate_html import validate_html # pylint: disable=invalid-name @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.remove_status_task.delay") @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") class StatusViews(TestCase): @@ -23,7 +24,7 @@ class StatusViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/test_updates.py b/bookwyrm/tests/views/test_updates.py index e7b466cc..d5d1d881 100644 --- a/bookwyrm/tests/views/test_updates.py +++ b/bookwyrm/tests/views/test_updates.py @@ -17,7 +17,7 @@ class UpdateViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_user.py b/bookwyrm/tests/views/test_user.py index ddb029cc..869d04af 100644 --- a/bookwyrm/tests/views/test_user.py +++ b/bookwyrm/tests/views/test_user.py @@ -20,7 +20,7 @@ class UserViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/test_wellknown.py b/bookwyrm/tests/views/test_wellknown.py index ecb6a67a..465f39b4 100644 --- a/bookwyrm/tests/views/test_wellknown.py +++ b/bookwyrm/tests/views/test_wellknown.py @@ -18,7 +18,7 @@ class WellknownViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/views/feed.py b/bookwyrm/views/feed.py index ba6c3af5..4dd76499 100644 --- a/bookwyrm/views/feed.py +++ b/bookwyrm/views/feed.py @@ -28,7 +28,9 @@ class Feed(View): settings_saved = False form = forms.FeedStatusTypesForm(request.POST, instance=request.user) if form.is_valid(): - form.save() + # workaround to avoid broadcasting this change + user = form.save(commit=False) + user.save(broadcast=False, update_fields=["feed_status_types"]) settings_saved = True return self.get(request, tab, settings_saved) From 074c2cfb957b0b4cb3851cc79fc8917b62263856 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 18:16:34 -0800 Subject: [PATCH 020/256] Gets updates view to 100% test coverage --- bookwyrm/tests/views/test_updates.py | 11 ++++++++++- bookwyrm/views/updates.py | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/bookwyrm/tests/views/test_updates.py b/bookwyrm/tests/views/test_updates.py index d5d1d881..4ca704fc 100644 --- a/bookwyrm/tests/views/test_updates.py +++ b/bookwyrm/tests/views/test_updates.py @@ -2,7 +2,7 @@ import json from unittest.mock import patch -from django.http import JsonResponse +from django.http import Http404, JsonResponse from django.test import TestCase from django.test.client import RequestFactory @@ -54,6 +54,7 @@ class UpdateViews(TestCase): "bookwyrm.activitystreams.ActivityStream.get_unread_count" ) as mock_count: with patch( + # pylint:disable=line-too-long "bookwyrm.activitystreams.ActivityStream.get_unread_count_by_status_type" ) as mock_count_by_status: mock_count.return_value = 3 @@ -64,3 +65,11 @@ class UpdateViews(TestCase): data = json.loads(result.getvalue()) self.assertEqual(data["count"], 3) self.assertEqual(data["count_by_type"]["review"], 5) + + def test_get_unread_status_count_invalid_stream(self): + """there are so many views, this just makes sure it LOADS""" + request = self.factory.get("") + request.user = self.local_user + + with self.assertRaises(Http404): + views.get_unread_status_count(request, "fish") diff --git a/bookwyrm/views/updates.py b/bookwyrm/views/updates.py index 2bbc5477..765865ef 100644 --- a/bookwyrm/views/updates.py +++ b/bookwyrm/views/updates.py @@ -1,6 +1,6 @@ """ endpoints for getting updates about activity """ from django.contrib.auth.decorators import login_required -from django.http import JsonResponse +from django.http import Http404, JsonResponse from bookwyrm import activitystreams @@ -21,7 +21,7 @@ def get_unread_status_count(request, stream="home"): """any unread statuses for this feed?""" stream = activitystreams.streams.get(stream) if not stream: - return JsonResponse({}) + raise Http404 return JsonResponse( { "count": stream.get_unread_count(request.user), From d9d0919ad4cd845ba3b8c4e5f09df56e62c1f1dd Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 19:14:10 -0800 Subject: [PATCH 021/256] More mocks for more tests --- bookwyrm/tests/lists_stream/test_signals.py | 2 +- bookwyrm/tests/lists_stream/test_stream.py | 2 +- bookwyrm/tests/lists_stream/test_tasks.py | 2 +- bookwyrm/tests/management/test_populate_lists_streams.py | 2 +- bookwyrm/tests/management/test_populate_streams.py | 2 +- bookwyrm/tests/views/admin/test_announcements.py | 2 +- bookwyrm/tests/views/admin/test_dashboard.py | 2 +- bookwyrm/tests/views/admin/test_email_blocks.py | 2 +- bookwyrm/tests/views/admin/test_federation.py | 2 +- bookwyrm/tests/views/admin/test_ip_blocklist.py | 2 +- bookwyrm/tests/views/admin/test_reports.py | 2 +- bookwyrm/tests/views/admin/test_user_admin.py | 2 +- bookwyrm/tests/views/books/test_book.py | 2 +- bookwyrm/tests/views/books/test_edit_book.py | 2 +- bookwyrm/tests/views/books/test_editions.py | 2 +- bookwyrm/tests/views/landing/test_invite.py | 2 +- bookwyrm/tests/views/landing/test_landing.py | 2 +- bookwyrm/tests/views/landing/test_login.py | 2 +- bookwyrm/tests/views/landing/test_password.py | 2 +- bookwyrm/tests/views/landing/test_register.py | 3 ++- bookwyrm/tests/views/preferences/test_block.py | 2 +- bookwyrm/tests/views/preferences/test_change_password.py | 2 +- bookwyrm/tests/views/preferences/test_delete_user.py | 2 +- bookwyrm/tests/views/preferences/test_edit_user.py | 2 +- bookwyrm/tests/views/shelf/test_shelf.py | 3 ++- bookwyrm/tests/views/shelf/test_shelf_actions.py | 5 +++-- 26 files changed, 30 insertions(+), 27 deletions(-) diff --git a/bookwyrm/tests/lists_stream/test_signals.py b/bookwyrm/tests/lists_stream/test_signals.py index 7640ea98..7d7cfee7 100644 --- a/bookwyrm/tests/lists_stream/test_signals.py +++ b/bookwyrm/tests/lists_stream/test_signals.py @@ -12,7 +12,7 @@ class ListsStreamSignals(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/lists_stream/test_stream.py b/bookwyrm/tests/lists_stream/test_stream.py index 25241793..e7157152 100644 --- a/bookwyrm/tests/lists_stream/test_stream.py +++ b/bookwyrm/tests/lists_stream/test_stream.py @@ -16,7 +16,7 @@ class ListsStream(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/lists_stream/test_tasks.py b/bookwyrm/tests/lists_stream/test_tasks.py index 1e5f7a98..70c112bd 100644 --- a/bookwyrm/tests/lists_stream/test_tasks.py +++ b/bookwyrm/tests/lists_stream/test_tasks.py @@ -11,7 +11,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/management/test_populate_lists_streams.py b/bookwyrm/tests/management/test_populate_lists_streams.py index 0a586d86..45c5eb80 100644 --- a/bookwyrm/tests/management/test_populate_lists_streams.py +++ b/bookwyrm/tests/management/test_populate_lists_streams.py @@ -14,7 +14,7 @@ class Activitystreams(TestCase): """we need some stuff""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index cee8b381..c527b27b 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -14,7 +14,7 @@ class Activitystreams(TestCase): """we need some stuff""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/views/admin/test_announcements.py b/bookwyrm/tests/views/admin/test_announcements.py index 44b5d5b6..08cab350 100644 --- a/bookwyrm/tests/views/admin/test_announcements.py +++ b/bookwyrm/tests/views/admin/test_announcements.py @@ -15,7 +15,7 @@ class AnnouncementViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_dashboard.py b/bookwyrm/tests/views/admin/test_dashboard.py index f0238eef..d05772c2 100644 --- a/bookwyrm/tests/views/admin/test_dashboard.py +++ b/bookwyrm/tests/views/admin/test_dashboard.py @@ -16,7 +16,7 @@ class DashboardViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_email_blocks.py b/bookwyrm/tests/views/admin/test_email_blocks.py index 6d676fd2..4fe9412e 100644 --- a/bookwyrm/tests/views/admin/test_email_blocks.py +++ b/bookwyrm/tests/views/admin/test_email_blocks.py @@ -17,7 +17,7 @@ class EmailBlocklistViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_federation.py b/bookwyrm/tests/views/admin/test_federation.py index fbbd540e..deed5bd3 100644 --- a/bookwyrm/tests/views/admin/test_federation.py +++ b/bookwyrm/tests/views/admin/test_federation.py @@ -19,7 +19,7 @@ class FederationViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_ip_blocklist.py b/bookwyrm/tests/views/admin/test_ip_blocklist.py index 25694d07..e23abd8b 100644 --- a/bookwyrm/tests/views/admin/test_ip_blocklist.py +++ b/bookwyrm/tests/views/admin/test_ip_blocklist.py @@ -16,7 +16,7 @@ class IPBlocklistViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_reports.py b/bookwyrm/tests/views/admin/test_reports.py index 8b9fe9f5..137d17cb 100644 --- a/bookwyrm/tests/views/admin/test_reports.py +++ b/bookwyrm/tests/views/admin/test_reports.py @@ -18,7 +18,7 @@ class ReportViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/admin/test_user_admin.py b/bookwyrm/tests/views/admin/test_user_admin.py index 486fe45e..4cb3702d 100644 --- a/bookwyrm/tests/views/admin/test_user_admin.py +++ b/bookwyrm/tests/views/admin/test_user_admin.py @@ -18,7 +18,7 @@ class UserAdminViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/books/test_book.py b/bookwyrm/tests/views/books/test_book.py index cb73e381..4d937071 100644 --- a/bookwyrm/tests/views/books/test_book.py +++ b/bookwyrm/tests/views/books/test_book.py @@ -28,7 +28,7 @@ class BookViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/books/test_edit_book.py b/bookwyrm/tests/views/books/test_edit_book.py index cd957858..cfb0d766 100644 --- a/bookwyrm/tests/views/books/test_edit_book.py +++ b/bookwyrm/tests/views/books/test_edit_book.py @@ -21,7 +21,7 @@ class EditBookViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/books/test_editions.py b/bookwyrm/tests/views/books/test_editions.py index 17f15654..70a95051 100644 --- a/bookwyrm/tests/views/books/test_editions.py +++ b/bookwyrm/tests/views/books/test_editions.py @@ -18,7 +18,7 @@ class BookViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/landing/test_invite.py b/bookwyrm/tests/views/landing/test_invite.py index a93821a9..a5877187 100644 --- a/bookwyrm/tests/views/landing/test_invite.py +++ b/bookwyrm/tests/views/landing/test_invite.py @@ -19,7 +19,7 @@ class InviteViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/landing/test_landing.py b/bookwyrm/tests/views/landing/test_landing.py index 82991917..37ce6cfc 100644 --- a/bookwyrm/tests/views/landing/test_landing.py +++ b/bookwyrm/tests/views/landing/test_landing.py @@ -18,7 +18,7 @@ class LandingViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/landing/test_login.py b/bookwyrm/tests/views/landing/test_login.py index 0f86fb79..24987c8e 100644 --- a/bookwyrm/tests/views/landing/test_login.py +++ b/bookwyrm/tests/views/landing/test_login.py @@ -21,7 +21,7 @@ class LoginViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/landing/test_password.py b/bookwyrm/tests/views/landing/test_password.py index f01565ef..b1f7e59f 100644 --- a/bookwyrm/tests/views/landing/test_password.py +++ b/bookwyrm/tests/views/landing/test_password.py @@ -21,7 +21,7 @@ class PasswordViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/landing/test_register.py b/bookwyrm/tests/views/landing/test_register.py index 99f38da2..deb16552 100644 --- a/bookwyrm/tests/views/landing/test_register.py +++ b/bookwyrm/tests/views/landing/test_register.py @@ -16,6 +16,7 @@ from bookwyrm.tests.validate_html import validate_html # pylint: disable=too-many-public-methods @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") class RegisterViews(TestCase): """login and password management""" @@ -24,7 +25,7 @@ class RegisterViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@your.domain.here", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/preferences/test_block.py b/bookwyrm/tests/views/preferences/test_block.py index 975142a1..262eee74 100644 --- a/bookwyrm/tests/views/preferences/test_block.py +++ b/bookwyrm/tests/views/preferences/test_block.py @@ -18,7 +18,7 @@ class BlockViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/preferences/test_change_password.py b/bookwyrm/tests/views/preferences/test_change_password.py index d13c2af5..61837c4e 100644 --- a/bookwyrm/tests/views/preferences/test_change_password.py +++ b/bookwyrm/tests/views/preferences/test_change_password.py @@ -17,7 +17,7 @@ class ChangePasswordViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/preferences/test_delete_user.py b/bookwyrm/tests/views/preferences/test_delete_user.py index b6d87ccd..95bfa4df 100644 --- a/bookwyrm/tests/views/preferences/test_delete_user.py +++ b/bookwyrm/tests/views/preferences/test_delete_user.py @@ -20,7 +20,7 @@ class DeleteUserViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/preferences/test_edit_user.py b/bookwyrm/tests/views/preferences/test_edit_user.py index 7a845fbe..11d33340 100644 --- a/bookwyrm/tests/views/preferences/test_edit_user.py +++ b/bookwyrm/tests/views/preferences/test_edit_user.py @@ -23,7 +23,7 @@ class EditUserViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/shelf/test_shelf.py b/bookwyrm/tests/views/shelf/test_shelf.py index ab88de0a..5f788391 100644 --- a/bookwyrm/tests/views/shelf/test_shelf.py +++ b/bookwyrm/tests/views/shelf/test_shelf.py @@ -14,6 +14,7 @@ from bookwyrm.tests.validate_html import validate_html @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class ShelfViews(TestCase): @@ -24,7 +25,7 @@ class ShelfViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", diff --git a/bookwyrm/tests/views/shelf/test_shelf_actions.py b/bookwyrm/tests/views/shelf/test_shelf_actions.py index 1a7d56fd..93ff0a38 100644 --- a/bookwyrm/tests/views/shelf/test_shelf_actions.py +++ b/bookwyrm/tests/views/shelf/test_shelf_actions.py @@ -12,6 +12,7 @@ from bookwyrm import forms, models, views @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") @patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.lists_stream.populate_lists_task.delay") @patch("bookwyrm.activitystreams.add_book_statuses_task.delay") @patch("bookwyrm.activitystreams.remove_book_statuses_task.delay") class ShelfActionViews(TestCase): @@ -22,7 +23,7 @@ class ShelfActionViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.com", @@ -178,7 +179,7 @@ class ShelfActionViews(TestCase): """delete a brand new custom shelf""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): rat = models.User.objects.create_user( "rat@local.com", "rat@mouse.mouse", From acde30887d70e948ace4c3e2765f8000c499c304 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 20:04:47 -0800 Subject: [PATCH 022/256] Importer tests --- .../tests/importers/test_goodreads_import.py | 2 +- bookwyrm/tests/importers/test_importer.py | 2 +- .../importers/test_librarything_import.py | 2 +- .../tests/importers/test_storygraph_import.py | 2 +- bookwyrm/tests/views/imports/test_import.py | 44 +++++++++++++--- .../tests/views/imports/test_import_review.py | 2 +- .../views/imports/test_import_troubleshoot.py | 2 +- bookwyrm/views/imports/import_data.py | 51 +++++++++---------- 8 files changed, 69 insertions(+), 38 deletions(-) diff --git a/bookwyrm/tests/importers/test_goodreads_import.py b/bookwyrm/tests/importers/test_goodreads_import.py index 0a421df4..04fb886b 100644 --- a/bookwyrm/tests/importers/test_goodreads_import.py +++ b/bookwyrm/tests/importers/test_goodreads_import.py @@ -30,7 +30,7 @@ class GoodreadsImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_importer.py b/bookwyrm/tests/importers/test_importer.py index 5c3b2031..87f0d209 100644 --- a/bookwyrm/tests/importers/test_importer.py +++ b/bookwyrm/tests/importers/test_importer.py @@ -33,7 +33,7 @@ class GenericImporter(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_librarything_import.py b/bookwyrm/tests/importers/test_librarything_import.py index 49354b36..57d55520 100644 --- a/bookwyrm/tests/importers/test_librarything_import.py +++ b/bookwyrm/tests/importers/test_librarything_import.py @@ -32,7 +32,7 @@ class LibrarythingImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mmai", "mmai@mmai.mmai", "password", local=True ) diff --git a/bookwyrm/tests/importers/test_storygraph_import.py b/bookwyrm/tests/importers/test_storygraph_import.py index 09cf32dc..e6d1c5c0 100644 --- a/bookwyrm/tests/importers/test_storygraph_import.py +++ b/bookwyrm/tests/importers/test_storygraph_import.py @@ -30,7 +30,7 @@ class StorygraphImport(TestCase): self.csv = open(datafile, "r", encoding=self.importer.encoding) with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True ) diff --git a/bookwyrm/tests/views/imports/test_import.py b/bookwyrm/tests/views/imports/test_import.py index b8b8b328..362cb199 100644 --- a/bookwyrm/tests/views/imports/test_import.py +++ b/bookwyrm/tests/views/imports/test_import.py @@ -1,13 +1,14 @@ """ test for app action functionality """ import pathlib from unittest.mock import patch + from django.core.files.uploadedfile import SimpleUploadedFile from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory -from bookwyrm.tests.validate_html import validate_html from bookwyrm import forms, models, views +from bookwyrm.tests.validate_html import validate_html class ImportViews(TestCase): @@ -18,7 +19,7 @@ class ImportViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", @@ -44,15 +45,29 @@ class ImportViews(TestCase): import_job = models.ImportJob.objects.create(user=self.local_user, mappings={}) request = self.factory.get("") request.user = self.local_user - with patch("bookwyrm.tasks.app.AsyncResult") as async_result: - async_result.return_value = [] - result = view(request, import_job.id) + + result = view(request, import_job.id) + self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) + def test_import_status_reformat(self): + """there are so many views, this just makes sure it LOADS""" + view = views.ImportStatus.as_view() + import_job = models.ImportJob.objects.create(user=self.local_user, mappings={}) + request = self.factory.post("") + request.user = self.local_user + with patch( + "bookwyrm.importers.goodreads_import.GoodreadsImporter.update_legacy_job" + ) as mock: + result = view(request, import_job.id) + self.assertEqual(mock.call_args[0][0], import_job) + + self.assertEqual(result.status_code, 302) + def test_start_import(self): - """retry failed items""" + """start a job""" view = views.Import.as_view() form = forms.ImportForm() form.data["source"] = "Goodreads" @@ -74,3 +89,20 @@ class ImportViews(TestCase): job = models.ImportJob.objects.get() self.assertFalse(job.include_reviews) self.assertEqual(job.privacy, "public") + + def test_retry_item(self): + """try again on a single row""" + job = models.ImportJob.objects.create(user=self.local_user, mappings={}) + item = models.ImportItem.objects.create( + index=0, + job=job, + book_guess=self.book, + fail_reason="no match", + data={}, + normalized_data={}, + ) + request = self.factory.post("") + request.user = self.local_user + with patch("bookwyrm.importers.importer.import_item_task.delay") as mock: + views.retry_item(request, job.id, item.id) + self.assertEqual(mock.call_count, 1) diff --git a/bookwyrm/tests/views/imports/test_import_review.py b/bookwyrm/tests/views/imports/test_import_review.py index 2ab48468..9ed4532e 100644 --- a/bookwyrm/tests/views/imports/test_import_review.py +++ b/bookwyrm/tests/views/imports/test_import_review.py @@ -16,7 +16,7 @@ class ImportManualReviewViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/tests/views/imports/test_import_troubleshoot.py b/bookwyrm/tests/views/imports/test_import_troubleshoot.py index 5359cc1e..b39f6d9e 100644 --- a/bookwyrm/tests/views/imports/test_import_troubleshoot.py +++ b/bookwyrm/tests/views/imports/test_import_troubleshoot.py @@ -16,7 +16,7 @@ class ImportTroubleshootViews(TestCase): self.factory = RequestFactory() with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse@local.com", "mouse@mouse.mouse", diff --git a/bookwyrm/views/imports/import_data.py b/bookwyrm/views/imports/import_data.py index 7f6a4d13..80386b3d 100644 --- a/bookwyrm/views/imports/import_data.py +++ b/bookwyrm/views/imports/import_data.py @@ -37,33 +37,32 @@ class Import(View): def post(self, request): """ingest a goodreads csv""" form = forms.ImportForm(request.POST, request.FILES) - if form.is_valid(): - include_reviews = request.POST.get("include_reviews") == "on" - privacy = request.POST.get("privacy") - source = request.POST.get("source") + if not form.is_valid(): + return HttpResponseBadRequest() - importer = None - if source == "LibraryThing": - importer = LibrarythingImporter() - elif source == "Storygraph": - importer = StorygraphImporter() - else: - # Default : Goodreads - importer = GoodreadsImporter() + include_reviews = request.POST.get("include_reviews") == "on" + privacy = request.POST.get("privacy") + source = request.POST.get("source") - try: - job = importer.create_job( - request.user, - TextIOWrapper( - request.FILES["csv_file"], encoding=importer.encoding - ), - include_reviews, - privacy, - ) - except (UnicodeDecodeError, ValueError, KeyError): - return HttpResponseBadRequest(_("Not a valid csv file")) + importer = None + if source == "LibraryThing": + importer = LibrarythingImporter() + elif source == "Storygraph": + importer = StorygraphImporter() + else: + # Default : Goodreads + importer = GoodreadsImporter() - importer.start_import(job) + try: + job = importer.create_job( + request.user, + TextIOWrapper(request.FILES["csv_file"], encoding=importer.encoding), + include_reviews, + privacy, + ) + except (UnicodeDecodeError, ValueError, KeyError): + return HttpResponseBadRequest(_("Not a valid csv file")) - return redirect(f"/import/{job.id}") - return HttpResponseBadRequest() + importer.start_import(job) + + return redirect(f"/import/{job.id}") From 5e6b28bbc0b392a37880015968825570c98db0ca Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 20:30:53 -0800 Subject: [PATCH 023/256] Prefs mocks --- bookwyrm/tests/activitypub/test_base_activity.py | 2 +- bookwyrm/tests/views/preferences/test_block.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bookwyrm/tests/activitypub/test_base_activity.py b/bookwyrm/tests/activitypub/test_base_activity.py index b951c7ab..973e57bf 100644 --- a/bookwyrm/tests/activitypub/test_base_activity.py +++ b/bookwyrm/tests/activitypub/test_base_activity.py @@ -31,7 +31,7 @@ class BaseActivity(TestCase): """we're probably going to re-use this so why copy/paste""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/views/preferences/test_block.py b/bookwyrm/tests/views/preferences/test_block.py index 262eee74..46de8f48 100644 --- a/bookwyrm/tests/views/preferences/test_block.py +++ b/bookwyrm/tests/views/preferences/test_block.py @@ -61,7 +61,9 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): + with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"), patch( + "bookwyrm.lists_stream.remove_user_lists_task.delay" + ): view(request, self.remote_user.id) block = models.UserBlocks.objects.get() self.assertEqual(block.user_subject, self.local_user) @@ -76,7 +78,9 @@ class BlockViews(TestCase): request = self.factory.post("") request.user = self.local_user - with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"): + with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"), patch( + "bookwyrm.lists_stream.add_user_lists_task.delay" + ): views.unblock(request, self.remote_user.id) self.assertFalse(models.UserBlocks.objects.exists()) From 0c193b6ce18c3793947cbf4dafdeee7976913d83 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 20:33:11 -0800 Subject: [PATCH 024/256] ActivityStream mocks --- bookwyrm/tests/activitystreams/test_abstractstream.py | 2 +- bookwyrm/tests/activitystreams/test_booksstream.py | 2 +- bookwyrm/tests/activitystreams/test_homestream.py | 2 +- bookwyrm/tests/activitystreams/test_localstream.py | 2 +- bookwyrm/tests/activitystreams/test_signals.py | 2 +- bookwyrm/tests/activitystreams/test_tasks.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bookwyrm/tests/activitystreams/test_abstractstream.py b/bookwyrm/tests/activitystreams/test_abstractstream.py index 17a1b587..2c5cf610 100644 --- a/bookwyrm/tests/activitystreams/test_abstractstream.py +++ b/bookwyrm/tests/activitystreams/test_abstractstream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_booksstream.py b/bookwyrm/tests/activitystreams/test_booksstream.py index 347e7a94..c001d6dd 100644 --- a/bookwyrm/tests/activitystreams/test_booksstream.py +++ b/bookwyrm/tests/activitystreams/test_booksstream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_homestream.py b/bookwyrm/tests/activitystreams/test_homestream.py index d48bdfba..10c806c8 100644 --- a/bookwyrm/tests/activitystreams/test_homestream.py +++ b/bookwyrm/tests/activitystreams/test_homestream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_localstream.py b/bookwyrm/tests/activitystreams/test_localstream.py index fa1a6741..d8bfb4fa 100644 --- a/bookwyrm/tests/activitystreams/test_localstream.py +++ b/bookwyrm/tests/activitystreams/test_localstream.py @@ -16,7 +16,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index 34aeb947..15f2b640 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -12,7 +12,7 @@ class ActivitystreamsSignals(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) diff --git a/bookwyrm/tests/activitystreams/test_tasks.py b/bookwyrm/tests/activitystreams/test_tasks.py index f5750763..af05cf18 100644 --- a/bookwyrm/tests/activitystreams/test_tasks.py +++ b/bookwyrm/tests/activitystreams/test_tasks.py @@ -11,7 +11,7 @@ class Activitystreams(TestCase): """use a test csv""" with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( "bookwyrm.activitystreams.populate_stream_task.delay" - ): + ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.local_user = models.User.objects.create_user( "mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse" ) From 59e6b67bc8936e13ceca52600e9d4883ff8b4cb9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 9 Dec 2021 20:38:44 -0800 Subject: [PATCH 025/256] Activitystreams mocks --- bookwyrm/tests/activitystreams/test_signals.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/bookwyrm/tests/activitystreams/test_signals.py b/bookwyrm/tests/activitystreams/test_signals.py index 15f2b640..c5c7e698 100644 --- a/bookwyrm/tests/activitystreams/test_signals.py +++ b/bookwyrm/tests/activitystreams/test_signals.py @@ -5,6 +5,8 @@ from bookwyrm import activitystreams, models @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +@patch("bookwyrm.lists_stream.add_user_lists_task.delay") +@patch("bookwyrm.lists_stream.remove_user_lists_task.delay") class ActivitystreamsSignals(TestCase): """using redis to build activity streams""" @@ -32,11 +34,11 @@ class ActivitystreamsSignals(TestCase): work = models.Work.objects.create(title="test work") self.book = models.Edition.objects.create(title="test book", parent_work=work) - def test_add_status_on_create_ignore(self, _): + def test_add_status_on_create_ignore(self, *_): """a new statuses has entered""" activitystreams.add_status_on_create(models.User, self.local_user, False) - def test_add_status_on_create_deleted(self, _): + def test_add_status_on_create_deleted(self, *_): """a new statuses has entered""" with patch("bookwyrm.activitystreams.remove_status_task.delay"): status = models.Status.objects.create( @@ -48,7 +50,7 @@ class ActivitystreamsSignals(TestCase): args = mock.call_args[0] self.assertEqual(args[0], status.id) - def test_add_status_on_create_created(self, _): + def test_add_status_on_create_created(self, *_): """a new statuses has entered""" status = models.Status.objects.create( user=self.remote_user, content="hi", privacy="public" @@ -60,7 +62,7 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args["args"][0], status.id) self.assertEqual(args["queue"], "high_priority") - def test_populate_streams_on_account_create(self, _): + def test_populate_streams_on_account_create(self, *_): """create streams for a user""" with patch("bookwyrm.activitystreams.populate_stream_task.delay") as mock: activitystreams.populate_streams_on_account_create( @@ -71,7 +73,7 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args[0], "books") self.assertEqual(args[1], self.local_user.id) - def test_remove_statuses_on_block(self, _): + def test_remove_statuses_on_block(self, *_): """don't show statuses from blocked users""" with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") as mock: models.UserBlocks.objects.create( @@ -83,7 +85,7 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args[0], self.local_user.id) self.assertEqual(args[1], self.remote_user.id) - def test_add_statuses_on_unblock(self, _): + def test_add_statuses_on_unblock(self, *_): """re-add statuses on unblock""" with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): block = models.UserBlocks.objects.create( @@ -100,7 +102,7 @@ class ActivitystreamsSignals(TestCase): self.assertEqual(args[1], self.remote_user.id) self.assertEqual(kwargs["stream_list"], ["local", "books"]) - def test_add_statuses_on_unblock_reciprocal_block(self, _): + def test_add_statuses_on_unblock_reciprocal_block(self, *_): """re-add statuses on unblock""" with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"): block = models.UserBlocks.objects.create( From 94250dab4240c65d8c67b8fe03b4c06acd316bf5 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Dec 2021 09:19:32 -0800 Subject: [PATCH 026/256] Mocks for list signals tests --- bookwyrm/tests/lists_stream/test_signals.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/bookwyrm/tests/lists_stream/test_signals.py b/bookwyrm/tests/lists_stream/test_signals.py index 7d7cfee7..91c6b48f 100644 --- a/bookwyrm/tests/lists_stream/test_signals.py +++ b/bookwyrm/tests/lists_stream/test_signals.py @@ -61,7 +61,8 @@ class ListsStreamSignals(TestCase): args = mock.call_args[0] self.assertEqual(args[0], self.local_user.id) - def test_remove_lists_on_block(self, _): + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + def test_remove_lists_on_block(self, *_): """don't show lists from blocked users""" with patch("bookwyrm.lists_stream.remove_user_lists_task.delay") as mock: models.UserBlocks.objects.create( @@ -73,7 +74,9 @@ class ListsStreamSignals(TestCase): self.assertEqual(args[0], self.local_user.id) self.assertEqual(args[1], self.remote_user.id) - def test_add_lists_on_unblock(self, _): + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + def test_add_lists_on_unblock(self, *_): """re-add lists on unblock""" with patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): block = models.UserBlocks.objects.create( @@ -88,7 +91,9 @@ class ListsStreamSignals(TestCase): self.assertEqual(args[0], self.local_user.id) self.assertEqual(args[1], self.remote_user.id) - def test_add_lists_on_unblock_reciprocal_block(self, _): + @patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") + @patch("bookwyrm.activitystreams.add_user_statuses_task.delay") + def test_add_lists_on_unblock_reciprocal_block(self, *_): """dont' re-add lists on unblock if there's a block the other way""" with patch("bookwyrm.lists_stream.remove_user_lists_task.delay"): block = models.UserBlocks.objects.create( From f7c8a550cf843c87edd3a12c09d74b304ef04cc1 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Dec 2021 09:34:17 -0800 Subject: [PATCH 027/256] Fixes references to populate lists task --- bookwyrm/management/commands/populate_lists_streams.py | 2 +- bookwyrm/management/commands/populate_streams.py | 2 +- bookwyrm/tests/management/test_populate_lists_streams.py | 6 ++++-- bookwyrm/tests/management/test_populate_streams.py | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bookwyrm/management/commands/populate_lists_streams.py b/bookwyrm/management/commands/populate_lists_streams.py index 1cf488df..502b3b92 100644 --- a/bookwyrm/management/commands/populate_lists_streams.py +++ b/bookwyrm/management/commands/populate_lists_streams.py @@ -13,7 +13,7 @@ def populate_lists_streams(): print("This may take a long time! Please be patient.") for user in users: print(".", end="") - lists_stream.populate_lists_stream_task.delay(user.id) + lists_stream.populate_lists_task.delay(user.id) class Command(BaseCommand): diff --git a/bookwyrm/management/commands/populate_streams.py b/bookwyrm/management/commands/populate_streams.py index 6b537650..5f83670c 100644 --- a/bookwyrm/management/commands/populate_streams.py +++ b/bookwyrm/management/commands/populate_streams.py @@ -14,7 +14,7 @@ def populate_streams(stream=None): print("This may take a long time! Please be patient.") for user in users: print(".", end="") - lists_stream.populate_lists_stream_task.delay(user.id) + lists_stream.populate_lists_task.delay(user.id) for stream_key in streams: print(".", end="") activitystreams.populate_stream_task.delay(stream_key, user.id) diff --git a/bookwyrm/tests/management/test_populate_lists_streams.py b/bookwyrm/tests/management/test_populate_lists_streams.py index 45c5eb80..f5047460 100644 --- a/bookwyrm/tests/management/test_populate_lists_streams.py +++ b/bookwyrm/tests/management/test_populate_lists_streams.py @@ -7,6 +7,8 @@ from bookwyrm.management.commands.populate_lists_streams import populate_lists_s @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") +@patch("bookwyrm.activitystreams.add_status_task.delay") +@patch("bookwyrm.activitystreams.populate_stream_task.delay") class Activitystreams(TestCase): """using redis to build activity streams""" @@ -45,10 +47,10 @@ class Activitystreams(TestCase): ) self.book = models.Edition.objects.create(title="test book") - def test_populate_streams(self, _): + def test_populate_streams(self, *_): """make sure the function on the redis manager gets called""" with patch( - "bookwyrm.lists_stream.populate_lists_stream_task.delay" + "bookwyrm.lists_stream.populate_lists_task.delay" ) as list_mock: populate_lists_streams() self.assertEqual(list_mock.call_count, 2) # 2 users diff --git a/bookwyrm/tests/management/test_populate_streams.py b/bookwyrm/tests/management/test_populate_streams.py index c527b27b..c20a21ac 100644 --- a/bookwyrm/tests/management/test_populate_streams.py +++ b/bookwyrm/tests/management/test_populate_streams.py @@ -55,7 +55,7 @@ class Activitystreams(TestCase): with patch( "bookwyrm.activitystreams.populate_stream_task.delay" ) as redis_mock, patch( - "bookwyrm.lists_stream.populate_lists_stream_task.delay" + "bookwyrm.lists_stream.populate_lists_task.delay" ) as list_mock: populate_streams() self.assertEqual(redis_mock.call_count, 6) # 2 users x 3 streams From b890e93533442aecc7e084c0603990fa55b67ee4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Dec 2021 09:53:17 -0800 Subject: [PATCH 028/256] Adds saved list view test --- .../management/test_populate_lists_streams.py | 4 +-- bookwyrm/tests/views/test_list_actions.py | 27 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/bookwyrm/tests/management/test_populate_lists_streams.py b/bookwyrm/tests/management/test_populate_lists_streams.py index f5047460..2cce7b7a 100644 --- a/bookwyrm/tests/management/test_populate_lists_streams.py +++ b/bookwyrm/tests/management/test_populate_lists_streams.py @@ -49,8 +49,6 @@ class Activitystreams(TestCase): def test_populate_streams(self, *_): """make sure the function on the redis manager gets called""" - with patch( - "bookwyrm.lists_stream.populate_lists_task.delay" - ) as list_mock: + with patch("bookwyrm.lists_stream.populate_lists_task.delay") as list_mock: populate_lists_streams() self.assertEqual(list_mock.call_count, 2) # 2 users diff --git a/bookwyrm/tests/views/test_list_actions.py b/bookwyrm/tests/views/test_list_actions.py index 0d04a8f2..7f57fae3 100644 --- a/bookwyrm/tests/views/test_list_actions.py +++ b/bookwyrm/tests/views/test_list_actions.py @@ -551,12 +551,7 @@ class ListActionViews(TestCase): ) self.assertTrue(self.list.listitem_set.exists()) - request = self.factory.post( - "", - { - "item": item.id, - }, - ) + request = self.factory.post("", {"item": item.id}) request.user = self.local_user with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): @@ -570,14 +565,22 @@ class ListActionViews(TestCase): book_list=self.list, user=self.local_user, book=self.book, order=1 ) self.assertTrue(self.list.listitem_set.exists()) - request = self.factory.post( - "", - { - "item": item.id, - }, - ) + request = self.factory.post("", {"item": item.id}) request.user = self.rat with self.assertRaises(PermissionDenied): views.list.remove_book(request, self.list.id) self.assertTrue(self.list.listitem_set.exists()) + + def test_save_unsave_list(self): + """bookmark a list""" + self.assertFalse(self.local_user.saved_lists.exists()) + request = self.factory.post("") + request.user = self.local_user + views.save_list(request, self.list.id) + self.local_user.refresh_from_db() + self.assertEqual(self.local_user.saved_lists.first(), self.list) + + views.unsave_list(request, self.list.id) + self.local_user.refresh_from_db() + self.assertFalse(self.local_user.saved_lists.exists()) From 9f04919becbb2c133ffd09745fdc97c8eff55b7f Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Dec 2021 11:44:38 -0800 Subject: [PATCH 029/256] Remove unrelated tests changes these will happen elsewhere --- bookwyrm/tests/views/imports/test_import.py | 42 ++--------------- bookwyrm/views/imports/import_data.py | 51 +++++++++++---------- 2 files changed, 31 insertions(+), 62 deletions(-) diff --git a/bookwyrm/tests/views/imports/test_import.py b/bookwyrm/tests/views/imports/test_import.py index 362cb199..763c2a52 100644 --- a/bookwyrm/tests/views/imports/test_import.py +++ b/bookwyrm/tests/views/imports/test_import.py @@ -1,14 +1,13 @@ """ test for app action functionality """ import pathlib from unittest.mock import patch - from django.core.files.uploadedfile import SimpleUploadedFile from django.template.response import TemplateResponse from django.test import TestCase from django.test.client import RequestFactory +from bookwyrm.tests.validate_html import validate_html from bookwyrm import forms, models, views -from bookwyrm.tests.validate_html import validate_html class ImportViews(TestCase): @@ -45,29 +44,15 @@ class ImportViews(TestCase): import_job = models.ImportJob.objects.create(user=self.local_user, mappings={}) request = self.factory.get("") request.user = self.local_user - - result = view(request, import_job.id) - + with patch("bookwyrm.tasks.app.AsyncResult") as async_result: + async_result.return_value = [] + result = view(request, import_job.id) self.assertIsInstance(result, TemplateResponse) validate_html(result.render()) self.assertEqual(result.status_code, 200) - def test_import_status_reformat(self): - """there are so many views, this just makes sure it LOADS""" - view = views.ImportStatus.as_view() - import_job = models.ImportJob.objects.create(user=self.local_user, mappings={}) - request = self.factory.post("") - request.user = self.local_user - with patch( - "bookwyrm.importers.goodreads_import.GoodreadsImporter.update_legacy_job" - ) as mock: - result = view(request, import_job.id) - self.assertEqual(mock.call_args[0][0], import_job) - - self.assertEqual(result.status_code, 302) - def test_start_import(self): - """start a job""" + """retry failed items""" view = views.Import.as_view() form = forms.ImportForm() form.data["source"] = "Goodreads" @@ -89,20 +74,3 @@ class ImportViews(TestCase): job = models.ImportJob.objects.get() self.assertFalse(job.include_reviews) self.assertEqual(job.privacy, "public") - - def test_retry_item(self): - """try again on a single row""" - job = models.ImportJob.objects.create(user=self.local_user, mappings={}) - item = models.ImportItem.objects.create( - index=0, - job=job, - book_guess=self.book, - fail_reason="no match", - data={}, - normalized_data={}, - ) - request = self.factory.post("") - request.user = self.local_user - with patch("bookwyrm.importers.importer.import_item_task.delay") as mock: - views.retry_item(request, job.id, item.id) - self.assertEqual(mock.call_count, 1) diff --git a/bookwyrm/views/imports/import_data.py b/bookwyrm/views/imports/import_data.py index 80386b3d..7f6a4d13 100644 --- a/bookwyrm/views/imports/import_data.py +++ b/bookwyrm/views/imports/import_data.py @@ -37,32 +37,33 @@ class Import(View): def post(self, request): """ingest a goodreads csv""" form = forms.ImportForm(request.POST, request.FILES) - if not form.is_valid(): - return HttpResponseBadRequest() + if form.is_valid(): + include_reviews = request.POST.get("include_reviews") == "on" + privacy = request.POST.get("privacy") + source = request.POST.get("source") - include_reviews = request.POST.get("include_reviews") == "on" - privacy = request.POST.get("privacy") - source = request.POST.get("source") + importer = None + if source == "LibraryThing": + importer = LibrarythingImporter() + elif source == "Storygraph": + importer = StorygraphImporter() + else: + # Default : Goodreads + importer = GoodreadsImporter() - importer = None - if source == "LibraryThing": - importer = LibrarythingImporter() - elif source == "Storygraph": - importer = StorygraphImporter() - else: - # Default : Goodreads - importer = GoodreadsImporter() + try: + job = importer.create_job( + request.user, + TextIOWrapper( + request.FILES["csv_file"], encoding=importer.encoding + ), + include_reviews, + privacy, + ) + except (UnicodeDecodeError, ValueError, KeyError): + return HttpResponseBadRequest(_("Not a valid csv file")) - try: - job = importer.create_job( - request.user, - TextIOWrapper(request.FILES["csv_file"], encoding=importer.encoding), - include_reviews, - privacy, - ) - except (UnicodeDecodeError, ValueError, KeyError): - return HttpResponseBadRequest(_("Not a valid csv file")) + importer.start_import(job) - importer.start_import(job) - - return redirect(f"/import/{job.id}") + return redirect(f"/import/{job.id}") + return HttpResponseBadRequest() From 8d6059ae32aaf47bfa34e03464d4c04ae20aa9cb Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 10 Dec 2021 12:32:05 -0800 Subject: [PATCH 030/256] Fixes mocks on group model tests --- bookwyrm/tests/models/test_group.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/bookwyrm/tests/models/test_group.py b/bookwyrm/tests/models/test_group.py index 3439a1bf..1fd071df 100644 --- a/bookwyrm/tests/models/test_group.py +++ b/bookwyrm/tests/models/test_group.py @@ -2,7 +2,7 @@ from unittest.mock import patch from django.test import TestCase -from bookwyrm import models +from bookwyrm import models, settings @patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async") @@ -19,16 +19,10 @@ class Group(TestCase): "mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse" ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.rat = models.User.objects.create_user( "rat", "rat@rat.rat", "ratword", local=True, localname="rat" ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.badger = models.User.objects.create_user( "badger", "badger@badger.badger", @@ -37,9 +31,6 @@ class Group(TestCase): localname="badger", ) - with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch( - "bookwyrm.activitystreams.populate_stream_task.delay" - ), patch("bookwyrm.lists_stream.populate_lists_task.delay"): self.capybara = models.User.objects.create_user( "capybara", "capybara@capybara.capybara", @@ -76,8 +67,7 @@ class Group(TestCase): models.GroupMember.objects.create(group=self.public_group, user=self.capybara) def test_group_members_can_see_private_groups(self, _): - """direct privacy group should not be excluded from group listings for group - members viewing""" + """direct privacy group should not be excluded from group listings for group members viewing""" rat_groups = models.Group.privacy_filter(self.rat).all() badger_groups = models.Group.privacy_filter(self.badger).all() @@ -86,8 +76,7 @@ class Group(TestCase): self.assertTrue(self.private_group in badger_groups) def test_group_members_can_see_followers_only_lists(self, _): - """follower-only group booklists should not be excluded from group booklist - listing for group members who do not follower list owner""" + """follower-only group booklists should not be excluded from group booklist listing for group members who do not follower list owner""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): followers_list = models.List.objects.create( @@ -107,8 +96,7 @@ class Group(TestCase): self.assertTrue(followers_list in capybara_lists) def test_group_members_can_see_private_lists(self, _): - """private group booklists should not be excluded from group booklist listing - for group members""" + """private group booklists should not be excluded from group booklist listing for group members""" with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): From 3358e4508673799f2f4156aa3d7703ced323a700 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 14 Dec 2021 09:31:57 -0800 Subject: [PATCH 031/256] Updates mocks on list stream tasks --- bookwyrm/tests/lists_stream/test_tasks.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/bookwyrm/tests/lists_stream/test_tasks.py b/bookwyrm/tests/lists_stream/test_tasks.py index 70c112bd..4c673a3a 100644 --- a/bookwyrm/tests/lists_stream/test_tasks.py +++ b/bookwyrm/tests/lists_stream/test_tasks.py @@ -4,6 +4,9 @@ from django.test import TestCase from bookwyrm import lists_stream, models +@patch("bookwyrm.activitystreams.populate_stream_task.delay") +@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") +@patch("bookwyrm.activitystreams.add_user_statuses_task.delay") class Activitystreams(TestCase): """using redis to build activity streams""" @@ -32,11 +35,12 @@ class Activitystreams(TestCase): inbox="https://example.com/users/rat/inbox", outbox="https://example.com/users/rat/outbox", ) - self.list = models.List.objects.create( - user=self.local_user, name="hi", privacy="public" - ) + with patch("bookwyrm.models.activitypub_mixin.broadcast_task.apply_async"): + self.list = models.List.objects.create( + user=self.local_user, name="hi", privacy="public" + ) - def test_populate_lists_task(self): + def test_populate_lists_task(self, *_): """populate lists cache""" with patch("bookwyrm.lists_stream.ListsStream.populate_streams") as mock: lists_stream.populate_lists_task(self.local_user.id) @@ -50,7 +54,7 @@ class Activitystreams(TestCase): args = mock.call_args[0] self.assertEqual(args[0], self.local_user) - def test_remove_list_task(self): + def test_remove_list_task(self, *_): """remove a list from all streams""" with patch( "bookwyrm.lists_stream.ListsStream.remove_object_from_related_stores" @@ -60,7 +64,7 @@ class Activitystreams(TestCase): args = mock.call_args[0] self.assertEqual(args[0], self.list) - def test_add_list_task(self): + def test_add_list_task(self, *_): """add a list to all streams""" with patch("bookwyrm.lists_stream.ListsStream.add_list") as mock: lists_stream.add_list_task(self.list.id) @@ -68,7 +72,7 @@ class Activitystreams(TestCase): args = mock.call_args[0] self.assertEqual(args[0], self.list) - def test_remove_user_lists_task(self): + def test_remove_user_lists_task(self, *_): """remove all lists by a user from another users' feeds""" with patch("bookwyrm.lists_stream.ListsStream.remove_user_lists") as mock: lists_stream.remove_user_lists_task( @@ -88,7 +92,7 @@ class Activitystreams(TestCase): self.assertEqual(args[0], self.local_user) self.assertEqual(args[1], self.another_user) - def test_add_user_lists_task(self): + def test_add_user_lists_task(self, *_): """add a user's lists to another users feeds""" with patch("bookwyrm.lists_stream.ListsStream.add_user_lists") as mock: lists_stream.add_user_lists_task(self.local_user.id, self.another_user.id) From 0012f4464d80b30b5f4b4698ef3b34ab43e99c16 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 14 Dec 2021 11:07:36 -0800 Subject: [PATCH 032/256] Consider group membership for list cache --- bookwyrm/lists_stream.py | 31 +++++++++++++++------- bookwyrm/tests/lists_stream/test_stream.py | 26 +++++++++++++++--- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/bookwyrm/lists_stream.py b/bookwyrm/lists_stream.py index da8cdb21..f44ef028 100644 --- a/bookwyrm/lists_stream.py +++ b/bookwyrm/lists_stream.py @@ -64,19 +64,32 @@ class ListsStream(RedisStore): Q(id__in=book_list.user.blocks.all()) | Q(blocks=book_list.user) ) - # TODO: groups - + group = book_list.group # only visible to the poster and mentioned users if book_list.privacy == "direct": - audience = audience.filter( - Q(id=book_list.user.id) # if the user is the post's author - ) + if group: + audience = audience.filter( + Q(id=book_list.user.id) # if the user is the post's author + | ~Q(groups=group.memberships) # if the user is in the group + ) + else: + audience = audience.filter( + Q(id=book_list.user.id) # if the user is the post's author + ) # only visible to the poster's followers and tagged users elif book_list.privacy == "followers": - audience = audience.filter( - Q(id=book_list.user.id) # if the user is the post's author - | Q(following=book_list.user) # if the user is following the author - ) + if group: + audience = audience.filter( + Q(id=book_list.user.id) # if the user is the list's owner + | Q(following=book_list.user) # if the user is following the pwmer + # if a user is in the group + | Q(memberships__group__id=book_list.group.id) + ) + else: + audience = audience.filter( + Q(id=book_list.user.id) # if the user is the list's owner + | Q(following=book_list.user) # if the user is following the pwmer + ) return audience.distinct() def get_stores_for_object(self, obj): diff --git a/bookwyrm/tests/lists_stream/test_stream.py b/bookwyrm/tests/lists_stream/test_stream.py index e7157152..d5357b17 100644 --- a/bookwyrm/tests/lists_stream/test_stream.py +++ b/bookwyrm/tests/lists_stream/test_stream.py @@ -92,7 +92,7 @@ class ListsStream(TestCase): book_list = models.List.objects.create( user=self.local_user, name="hi", - privacy="direct", + privacy="followers", ) users = self.stream.get_audience(book_list) self.assertTrue(self.local_user in users) @@ -105,9 +105,29 @@ class ListsStream(TestCase): book_list = models.List.objects.create( user=self.remote_user, name="hi", - privacy="direct", + privacy="followers", + ) + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) + self.assertFalse(self.another_user in users) + + def test_get_audience_followers_with_group(self, *_): + """get a list of users that should see a list""" + group = models.Group.objects.create(name="test group", user=self.remote_user) + models.GroupMember.objects.create( + group=group, + user=self.local_user, + ) + + book_list = models.List.objects.create( + user=self.remote_user, name="hi", privacy="followers", curation="group" ) users = self.stream.get_audience(book_list) self.assertFalse(self.local_user in users) + + book_list.group = group + book_list.save(broadcast=False) + + users = self.stream.get_audience(book_list) + self.assertTrue(self.local_user in users) self.assertFalse(self.another_user in users) - self.assertFalse(self.remote_user in users) From 65ec626573f02a2d6381a9e49bc40d1bdfbb09d6 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Tue, 14 Dec 2021 11:11:05 -0800 Subject: [PATCH 033/256] Don't trim stream if max length is unset --- bookwyrm/redis_store.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bookwyrm/redis_store.py b/bookwyrm/redis_store.py index 78f373a2..3b1b54a4 100644 --- a/bookwyrm/redis_store.py +++ b/bookwyrm/redis_store.py @@ -27,7 +27,8 @@ class RedisStore(ABC): # add the status to the feed pipeline.zadd(store, value) # trim the store - pipeline.zremrangebyrank(store, 0, -1 * self.max_length) + if self.max_length: + pipeline.zremrangebyrank(store, 0, -1 * self.max_length) if not execute: return pipeline # and go! @@ -46,7 +47,7 @@ class RedisStore(ABC): pipeline = r.pipeline() for obj in objs[: self.max_length]: pipeline.zadd(store, self.get_value(obj)) - if objs: + if objs and self.max_length: pipeline.zremrangebyrank(store, 0, -1 * self.max_length) pipeline.execute() @@ -70,7 +71,7 @@ class RedisStore(ABC): pipeline.zadd(store, self.get_value(obj)) # only trim the store if objects were added - if queryset.exists(): + if queryset.exists() and self.max_length: pipeline.zremrangebyrank(store, 0, -1 * self.max_length) pipeline.execute() From ea457eae588ee195f2cf606236ff748ecad78111 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 16 Dec 2021 10:40:20 -0800 Subject: [PATCH 034/256] Adds prettier package --- package.json | 3 +- yarn.lock | 3382 +++++++++++++++++++++++++------------------------- 2 files changed, 1717 insertions(+), 1668 deletions(-) diff --git a/package.json b/package.json index 119bb512..3028f868 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,11 @@ }, "devDependencies": { "eslint": "^7.23.0", + "prettier": "2.5.1", "stylelint": "^13.12.0", "stylelint-config-standard": "^21.0.0", "stylelint-order": "^4.1.0", - "watch": "^1.0.2" + "watch": "^0.13.0" }, "dependencies": { "merge": "2.1.1", diff --git a/yarn.lock b/yarn.lock index d25fbfb6..0de8a9d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,29 +2,29 @@ # yarn lockfile v1 -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== +"@babel/code-frame@^7.0.0", "@babel/code-frame@7.12.11": + "integrity" "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" + "version" "7.12.11" dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" - integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== +"@babel/code-frame@^7.12.13": + "integrity" "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==" + "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz" + "version" "7.12.13" dependencies: "@babel/highlight" "^7.12.13" "@babel/compat-data@^7.13.15": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.0.tgz#a901128bce2ad02565df95e6ecbf195cf9465919" - integrity sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q== + "integrity" "sha512-vu9V3uMM/1o5Hl5OekMUowo3FqXLJSw+s+66nt0fSWVWTtmosdzn45JHOB3cPtZoe6CTBDzvSw0RdOY85Q37+Q==" + "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.0.tgz" + "version" "7.14.0" -"@babel/core@>=7.9.0": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38" - integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg== +"@babel/core@^7.0.0", "@babel/core@>=7.9.0": + "integrity" "sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg==" + "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.14.3.tgz" + "version" "7.14.3" dependencies: "@babel/code-frame" "^7.12.13" "@babel/generator" "^7.14.3" @@ -35,66 +35,66 @@ "@babel/template" "^7.12.13" "@babel/traverse" "^7.14.2" "@babel/types" "^7.14.2" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" + "convert-source-map" "^1.7.0" + "debug" "^4.1.0" + "gensync" "^1.0.0-beta.2" + "json5" "^2.1.2" + "semver" "^6.3.0" + "source-map" "^0.5.0" "@babel/generator@^7.14.2", "@babel/generator@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.3.tgz#0c2652d91f7bddab7cccc6ba8157e4f40dcedb91" - integrity sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA== + "integrity" "sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA==" + "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.14.3.tgz" + "version" "7.14.3" dependencies: "@babel/types" "^7.14.2" - jsesc "^2.5.1" - source-map "^0.5.0" + "jsesc" "^2.5.1" + "source-map" "^0.5.0" "@babel/helper-compilation-targets@^7.13.16": - version "7.13.16" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz#6e91dccf15e3f43e5556dffe32d860109887563c" - integrity sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA== + "integrity" "sha512-3gmkYIrpqsLlieFwjkGgLaSHmhnvlAYzZLlYVjlW+QwI+1zE17kGxuJGmIqDQdYp56XdmGeD+Bswx0UTyG18xA==" + "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.16.tgz" + "version" "7.13.16" dependencies: "@babel/compat-data" "^7.13.15" "@babel/helper-validator-option" "^7.12.17" - browserslist "^4.14.5" - semver "^6.3.0" + "browserslist" "^4.14.5" + "semver" "^6.3.0" "@babel/helper-function-name@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz#397688b590760b6ef7725b5f0860c82427ebaac2" - integrity sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ== + "integrity" "sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ==" + "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz" + "version" "7.14.2" dependencies: "@babel/helper-get-function-arity" "^7.12.13" "@babel/template" "^7.12.13" "@babel/types" "^7.14.2" "@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== + "integrity" "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==" + "resolved" "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz" + "version" "7.12.13" dependencies: "@babel/types" "^7.12.13" "@babel/helper-member-expression-to-functions@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" - integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== + "integrity" "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==" + "resolved" "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz" + "version" "7.13.12" dependencies: "@babel/types" "^7.13.12" "@babel/helper-module-imports@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" - integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== + "integrity" "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz" + "version" "7.13.12" dependencies: "@babel/types" "^7.13.12" "@babel/helper-module-transforms@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz#ac1cc30ee47b945e3e0c4db12fa0c5389509dfe5" - integrity sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA== + "integrity" "sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA==" + "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz" + "version" "7.14.2" dependencies: "@babel/helper-module-imports" "^7.13.12" "@babel/helper-replace-supers" "^7.13.12" @@ -106,16 +106,16 @@ "@babel/types" "^7.14.2" "@babel/helper-optimise-call-expression@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" - integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== + "integrity" "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==" + "resolved" "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz" + "version" "7.12.13" dependencies: "@babel/types" "^7.12.13" "@babel/helper-replace-supers@^7.13.12": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz#ca17b318b859d107f0e9b722d58cf12d94436600" - integrity sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA== + "integrity" "sha512-Rlh8qEWZSTfdz+tgNV/N4gz1a0TMNwCUcENhMjHTHKp3LseYH5Jha0NSlyTQWMnjbYcwFt+bqAMqSLHVXkQ6UA==" + "resolved" "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.14.3.tgz" + "version" "7.14.3" dependencies: "@babel/helper-member-expression-to-functions" "^7.13.12" "@babel/helper-optimise-call-expression" "^7.12.13" @@ -123,65 +123,65 @@ "@babel/types" "^7.14.2" "@babel/helper-simple-access@^7.13.12": - version "7.13.12" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" - integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== + "integrity" "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==" + "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz" + "version" "7.13.12" dependencies: "@babel/types" "^7.13.12" "@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== + "integrity" "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==" + "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz" + "version" "7.12.13" dependencies: "@babel/types" "^7.12.13" "@babel/helper-validator-identifier@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" - integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== + "integrity" "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz" + "version" "7.14.0" "@babel/helper-validator-option@^7.12.17": - version "7.12.17" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" - integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== + "integrity" "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==" + "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz" + "version" "7.12.17" "@babel/helpers@^7.14.0": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" - integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== + "integrity" "sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg==" + "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.14.0.tgz" + "version" "7.14.0" dependencies: "@babel/template" "^7.12.13" "@babel/traverse" "^7.14.0" "@babel/types" "^7.14.0" "@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": - version "7.14.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" - integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== + "integrity" "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==" + "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz" + "version" "7.14.0" dependencies: "@babel/helper-validator-identifier" "^7.14.0" - chalk "^2.0.0" - js-tokens "^4.0.0" + "chalk" "^2.0.0" + "js-tokens" "^4.0.0" "@babel/parser@^7.12.13", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3": - version "7.14.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.3.tgz#9b530eecb071fd0c93519df25c5ff9f14759f298" - integrity sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ== + "integrity" "sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ==" + "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.14.3.tgz" + "version" "7.14.3" "@babel/template@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" - integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== + "integrity" "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==" + "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz" + "version" "7.12.13" dependencies: "@babel/code-frame" "^7.12.13" "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.2.tgz#9201a8d912723a831c2679c7ebbf2fe1416d765b" - integrity sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA== + "integrity" "sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA==" + "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.14.2.tgz" + "version" "7.14.2" dependencies: "@babel/code-frame" "^7.12.13" "@babel/generator" "^7.14.2" @@ -189,2034 +189,2082 @@ "@babel/helper-split-export-declaration" "^7.12.13" "@babel/parser" "^7.14.2" "@babel/types" "^7.14.2" - debug "^4.1.0" - globals "^11.1.0" + "debug" "^4.1.0" + "globals" "^11.1.0" "@babel/types@^7.12.13", "@babel/types@^7.13.12", "@babel/types@^7.14.0", "@babel/types@^7.14.2": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.2.tgz#4208ae003107ef8a057ea8333e56eb64d2f6a2c3" - integrity sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw== + "integrity" "sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw==" + "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.14.2.tgz" + "version" "7.14.2" dependencies: "@babel/helper-validator-identifier" "^7.14.0" - to-fast-properties "^2.0.0" + "to-fast-properties" "^2.0.0" "@eslint/eslintrc@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14" - integrity sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ== + "integrity" "sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ==" + "resolved" "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz" + "version" "0.4.1" dependencies: - ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" + "ajv" "^6.12.4" + "debug" "^4.1.1" + "espree" "^7.3.0" + "globals" "^12.1.0" + "ignore" "^4.0.6" + "import-fresh" "^3.2.1" + "js-yaml" "^3.13.1" + "minimatch" "^3.0.4" + "strip-json-comments" "^3.1.1" "@nodelib/fs.scandir@2.1.4": - version "2.1.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69" - integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA== + "integrity" "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz" + "version" "2.1.4" dependencies: "@nodelib/fs.stat" "2.0.4" - run-parallel "^1.1.9" + "run-parallel" "^1.1.9" -"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz#a3f2dd61bab43b8db8fa108a121cfffe4c676655" - integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.4": + "integrity" "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz" + "version" "2.0.4" "@nodelib/fs.walk@^1.2.3": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz#cce9396b30aa5afe9e3756608f5831adcb53d063" - integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow== + "integrity" "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==" + "resolved" "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz" + "version" "1.2.6" dependencies: "@nodelib/fs.scandir" "2.1.4" - fastq "^1.6.0" + "fastq" "^1.6.0" "@stylelint/postcss-css-in-js@^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" - integrity sha512-nEhsFoJurt8oUmieT8qy4nk81WRHmJynmVwn/Vts08PL9fhgIsMhk1GId5yAN643OzqEEb5S/6At2TZW7pqPDA== + "integrity" "sha512-nEhsFoJurt8oUmieT8qy4nk81WRHmJynmVwn/Vts08PL9fhgIsMhk1GId5yAN643OzqEEb5S/6At2TZW7pqPDA==" + "resolved" "https://registry.npmjs.org/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz" + "version" "0.37.2" dependencies: "@babel/core" ">=7.9.0" "@stylelint/postcss-markdown@^0.36.2": - version "0.36.2" - resolved "https://registry.yarnpkg.com/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz#0a540c4692f8dcdfc13c8e352c17e7bfee2bb391" - integrity sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ== + "integrity" "sha512-2kGbqUVJUGE8dM+bMzXG/PYUWKkjLIkRLWNh39OaADkiabDRdw8ATFCgbMz5xdIcvwspPAluSL7uY+ZiTWdWmQ==" + "resolved" "https://registry.npmjs.org/@stylelint/postcss-markdown/-/postcss-markdown-0.36.2.tgz" + "version" "0.36.2" dependencies: - remark "^13.0.0" - unist-util-find-all-after "^3.0.2" + "remark" "^13.0.0" + "unist-util-find-all-after" "^3.0.2" "@types/mdast@^3.0.0": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb" - integrity sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw== + "integrity" "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==" + "resolved" "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz" + "version" "3.0.3" dependencies: "@types/unist" "*" "@types/minimist@^1.2.0": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" - integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== + "integrity" "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==" + "resolved" "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz" + "version" "1.2.1" "@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" - integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + "integrity" "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" + "resolved" "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz" + "version" "2.4.0" "@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + "integrity" "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" + "resolved" "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" + "version" "4.0.0" "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" - integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== + "integrity" "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==" + "resolved" "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz" + "version" "2.0.3" -acorn-jsx@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== +"acorn-jsx@^5.3.1": + "integrity" "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==" + "resolved" "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz" + "version" "5.3.1" -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^7.4.0": + "integrity" "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + "resolved" "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + "version" "7.4.1" -ajv@^6.10.0, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== +"ajv@^6.10.0", "ajv@^6.12.4": + "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==" + "resolved" "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + "version" "6.12.6" dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" + "fast-deep-equal" "^3.1.1" + "fast-json-stable-stringify" "^2.0.0" + "json-schema-traverse" "^0.4.1" + "uri-js" "^4.2.2" -ajv@^8.0.1: - version "8.5.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.5.0.tgz#695528274bcb5afc865446aa275484049a18ae4b" - integrity sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ== +"ajv@^8.0.1": + "integrity" "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==" + "resolved" "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz" + "version" "8.5.0" dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" + "fast-deep-equal" "^3.1.1" + "json-schema-traverse" "^1.0.0" + "require-from-string" "^2.0.2" + "uri-js" "^4.2.2" -ansi-colors@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +"ansi-colors@^4.1.1": + "integrity" "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==" + "resolved" "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" + "version" "4.1.1" -ansi-regex@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +"ansi-regex@^5.0.0": + "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + "version" "5.0.1" -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== +"ansi-styles@^3.2.1": + "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + "version" "3.2.1" dependencies: - color-convert "^1.9.0" + "color-convert" "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== +"ansi-styles@^4.0.0", "ansi-styles@^4.1.0": + "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==" + "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + "version" "4.3.0" dependencies: - color-convert "^2.0.1" + "color-convert" "^2.0.1" -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== +"argparse@^1.0.7": + "integrity" "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==" + "resolved" "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + "version" "1.0.10" dependencies: - sprintf-js "~1.0.2" + "sprintf-js" "~1.0.2" -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +"array-union@^2.1.0": + "integrity" "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + "resolved" "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + "version" "2.1.0" -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +"arrify@^1.0.1": + "integrity" "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + "resolved" "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + "version" "1.0.1" -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +"astral-regex@^2.0.0": + "integrity" "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + "resolved" "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" + "version" "2.0.0" -autoprefixer@^9.8.6: - version "9.8.6" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" - integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== +"autoprefixer@^9.8.6": + "integrity" "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==" + "resolved" "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz" + "version" "9.8.6" dependencies: - browserslist "^4.12.0" - caniuse-lite "^1.0.30001109" - colorette "^1.2.1" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.32" - postcss-value-parser "^4.1.0" + "browserslist" "^4.12.0" + "caniuse-lite" "^1.0.30001109" + "colorette" "^1.2.1" + "normalize-range" "^0.1.2" + "num2fraction" "^1.2.2" + "postcss" "^7.0.32" + "postcss-value-parser" "^4.1.0" -bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== +"bail@^1.0.0": + "integrity" "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==" + "resolved" "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz" + "version" "1.0.5" -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +"balanced-match@^1.0.0": + "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + "version" "1.0.2" -balanced-match@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" - integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== +"balanced-match@^2.0.0": + "integrity" "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==" + "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz" + "version" "2.0.0" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +"brace-expansion@^1.1.7": + "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==" + "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + "version" "1.1.11" dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" + "balanced-match" "^1.0.0" + "concat-map" "0.0.1" -braces@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +"braces@^3.0.1": + "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==" + "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + "version" "3.0.2" dependencies: - fill-range "^7.0.1" + "fill-range" "^7.0.1" -browserslist@^4.12.0, browserslist@^4.14.5: - version "4.16.6" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" - integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== +"browserslist@^4.12.0", "browserslist@^4.14.5": + "integrity" "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==" + "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz" + "version" "4.16.6" dependencies: - caniuse-lite "^1.0.30001219" - colorette "^1.2.2" - electron-to-chromium "^1.3.723" - escalade "^3.1.1" - node-releases "^1.1.71" + "caniuse-lite" "^1.0.30001219" + "colorette" "^1.2.2" + "electron-to-chromium" "^1.3.723" + "escalade" "^3.1.1" + "node-releases" "^1.1.71" -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +"callsites@^3.0.0": + "integrity" "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + "resolved" "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + "version" "3.1.0" -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== +"camelcase-keys@^6.2.2": + "integrity" "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==" + "resolved" "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz" + "version" "6.2.2" dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" + "camelcase" "^5.3.1" + "map-obj" "^4.0.0" + "quick-lru" "^4.0.1" -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +"camelcase@^5.3.1": + "integrity" "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + "version" "5.3.1" -caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001219: - version "1.0.30001228" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz#bfdc5942cd3326fa51ee0b42fbef4da9d492a7fa" - integrity sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A== +"caniuse-lite@^1.0.30001109", "caniuse-lite@^1.0.30001219": + "integrity" "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==" + "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz" + "version" "1.0.30001228" -chalk@^2.0.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== +"chalk@^2.0.0": + "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + "version" "2.4.2" dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + "ansi-styles" "^3.2.1" + "escape-string-regexp" "^1.0.5" + "supports-color" "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" - integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== +"chalk@^4.0.0", "chalk@^4.1.0", "chalk@^4.1.1": + "integrity" "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==" + "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz" + "version" "4.1.1" dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" + "ansi-styles" "^4.1.0" + "supports-color" "^7.1.0" -character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== +"character-entities-legacy@^1.0.0": + "integrity" "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==" + "resolved" "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz" + "version" "1.1.4" -character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== +"character-entities@^1.0.0": + "integrity" "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==" + "resolved" "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz" + "version" "1.2.4" -character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== +"character-reference-invalid@^1.0.0": + "integrity" "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==" + "resolved" "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz" + "version" "1.1.4" -clone-regexp@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f" - integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q== +"clone-regexp@^2.1.0": + "integrity" "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==" + "resolved" "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz" + "version" "2.2.0" dependencies: - is-regexp "^2.0.0" + "is-regexp" "^2.0.0" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== +"color-convert@^1.9.0": + "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + "version" "1.9.3" dependencies: - color-name "1.1.3" + "color-name" "1.1.3" -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== +"color-convert@^2.0.1": + "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==" + "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + "version" "2.0.1" dependencies: - color-name "~1.1.4" + "color-name" "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +"color-name@~1.1.4": + "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + "version" "1.1.4" -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +"color-name@1.1.3": + "integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + "version" "1.1.3" -colorette@^1.2.1, colorette@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" - integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== +"colorette@^1.2.1", "colorette@^1.2.2": + "integrity" "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + "resolved" "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz" + "version" "1.2.2" -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +"concat-map@0.0.1": + "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "version" "0.0.1" -convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== +"convert-source-map@^1.7.0": + "integrity" "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==" + "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz" + "version" "1.7.0" dependencies: - safe-buffer "~5.1.1" + "safe-buffer" "~5.1.1" -cosmiconfig@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" - integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== +"cosmiconfig@^7.0.0": + "integrity" "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==" + "resolved" "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz" + "version" "7.0.0" dependencies: "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" + "import-fresh" "^3.2.1" + "parse-json" "^5.0.0" + "path-type" "^4.0.0" + "yaml" "^1.10.0" -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +"cross-spawn@^7.0.2": + "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==" + "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + "version" "7.0.3" dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" + "path-key" "^3.1.0" + "shebang-command" "^2.0.0" + "which" "^2.0.1" -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== +"cssesc@^3.0.0": + "integrity" "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + "resolved" "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" + "version" "3.0.0" -debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== +"debug@^4.0.0", "debug@^4.0.1", "debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.1": + "integrity" "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" + "version" "4.3.1" dependencies: - ms "2.1.2" + "ms" "2.1.2" -decamelize-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= +"decamelize-keys@^1.1.0": + "integrity" "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=" + "resolved" "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz" + "version" "1.1.0" dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" + "decamelize" "^1.1.0" + "map-obj" "^1.0.0" -decamelize@^1.1.0, decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +"decamelize@^1.1.0", "decamelize@^1.2.0": + "integrity" "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "resolved" "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + "version" "1.2.0" -deep-is@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +"deep-is@^0.1.3": + "integrity" "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "resolved" "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + "version" "0.1.3" -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== +"dir-glob@^3.0.1": + "integrity" "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==" + "resolved" "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + "version" "3.0.1" dependencies: - path-type "^4.0.0" + "path-type" "^4.0.0" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== +"doctrine@^3.0.0": + "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==" + "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + "version" "3.0.0" dependencies: - esutils "^2.0.2" + "esutils" "^2.0.2" -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== +"dom-serializer@0": + "integrity" "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==" + "resolved" "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz" + "version" "0.2.2" dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" + "domelementtype" "^2.0.1" + "entities" "^2.0.0" -domelementtype@1, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== +"domelementtype@^1.3.1", "domelementtype@1": + "integrity" "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + "resolved" "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz" + "version" "1.3.1" -domelementtype@^2.0.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== +"domelementtype@^2.0.1": + "integrity" "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + "resolved" "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz" + "version" "2.2.0" -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== +"domhandler@^2.3.0": + "integrity" "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==" + "resolved" "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz" + "version" "2.4.2" dependencies: - domelementtype "1" + "domelementtype" "1" -domutils@^1.5.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== +"domutils@^1.5.1": + "integrity" "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==" + "resolved" "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz" + "version" "1.7.0" dependencies: - dom-serializer "0" - domelementtype "1" + "dom-serializer" "0" + "domelementtype" "1" -electron-to-chromium@^1.3.723: - version "1.3.735" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.735.tgz#fa1a8660f2790662291cb2136f0e446a444cdfdc" - integrity sha512-cp7MWzC3NseUJV2FJFgaiesdrS+A8ZUjX5fLAxdRlcaPDkaPGFplX930S5vf84yqDp4LjuLdKouWuVOTwUfqHQ== +"electron-to-chromium@^1.3.723": + "integrity" "sha512-cp7MWzC3NseUJV2FJFgaiesdrS+A8ZUjX5fLAxdRlcaPDkaPGFplX930S5vf84yqDp4LjuLdKouWuVOTwUfqHQ==" + "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.735.tgz" + "version" "1.3.735" -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +"emoji-regex@^8.0.0": + "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + "version" "8.0.0" -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== +"enquirer@^2.3.5": + "integrity" "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==" + "resolved" "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" + "version" "2.3.6" dependencies: - ansi-colors "^4.1.1" + "ansi-colors" "^4.1.1" -entities@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== +"entities@^1.1.1": + "integrity" "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "resolved" "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz" + "version" "1.1.2" -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +"entities@^2.0.0": + "integrity" "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" + "resolved" "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" + "version" "2.2.0" -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== +"error-ex@^1.3.1": + "integrity" "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==" + "resolved" "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + "version" "1.3.2" dependencies: - is-arrayish "^0.2.1" + "is-arrayish" "^0.2.1" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +"escalade@^3.1.1": + "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + "version" "3.1.1" -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +"escape-string-regexp@^1.0.5": + "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "version" "1.0.5" -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== +"eslint-scope@^5.1.1": + "integrity" "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==" + "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + "version" "5.1.1" dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" + "esrecurse" "^4.3.0" + "estraverse" "^4.1.1" -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== +"eslint-utils@^2.1.0": + "integrity" "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==" + "resolved" "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" + "version" "2.1.0" dependencies: - eslint-visitor-keys "^1.1.0" + "eslint-visitor-keys" "^1.1.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== +"eslint-visitor-keys@^1.1.0": + "integrity" "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + "version" "1.3.0" -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== +"eslint-visitor-keys@^1.3.0": + "integrity" "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + "version" "1.3.0" -eslint@^7.23.0: - version "7.26.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.26.0.tgz#d416fdcdcb3236cd8f282065312813f8c13982f6" - integrity sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg== +"eslint-visitor-keys@^2.0.0": + "integrity" "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==" + "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + "version" "2.1.0" + +"eslint@^7.23.0": + "integrity" "sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg==" + "resolved" "https://registry.npmjs.org/eslint/-/eslint-7.26.0.tgz" + "version" "7.26.0" dependencies: "@babel/code-frame" "7.12.11" "@eslint/eslintrc" "^0.4.1" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.21" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.4" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" + "ajv" "^6.10.0" + "chalk" "^4.0.0" + "cross-spawn" "^7.0.2" + "debug" "^4.0.1" + "doctrine" "^3.0.0" + "enquirer" "^2.3.5" + "eslint-scope" "^5.1.1" + "eslint-utils" "^2.1.0" + "eslint-visitor-keys" "^2.0.0" + "espree" "^7.3.1" + "esquery" "^1.4.0" + "esutils" "^2.0.2" + "file-entry-cache" "^6.0.1" + "functional-red-black-tree" "^1.0.1" + "glob-parent" "^5.0.0" + "globals" "^13.6.0" + "ignore" "^4.0.6" + "import-fresh" "^3.0.0" + "imurmurhash" "^0.1.4" + "is-glob" "^4.0.0" + "js-yaml" "^3.13.1" + "json-stable-stringify-without-jsonify" "^1.0.1" + "levn" "^0.4.1" + "lodash" "^4.17.21" + "minimatch" "^3.0.4" + "natural-compare" "^1.4.0" + "optionator" "^0.9.1" + "progress" "^2.0.0" + "regexpp" "^3.1.0" + "semver" "^7.2.1" + "strip-ansi" "^6.0.0" + "strip-json-comments" "^3.1.0" + "table" "^6.0.4" + "text-table" "^0.2.0" + "v8-compile-cache" "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +"espree@^7.3.0", "espree@^7.3.1": + "integrity" "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==" + "resolved" "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" + "version" "7.3.1" dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + "acorn" "^7.4.0" + "acorn-jsx" "^5.3.1" + "eslint-visitor-keys" "^1.3.0" -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +"esprima@^4.0.0": + "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + "version" "4.0.1" -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +"esquery@^1.4.0": + "integrity" "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==" + "resolved" "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz" + "version" "1.4.0" dependencies: - estraverse "^5.1.0" + "estraverse" "^5.1.0" -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== +"esrecurse@^4.3.0": + "integrity" "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==" + "resolved" "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + "version" "4.3.0" dependencies: - estraverse "^5.2.0" + "estraverse" "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== +"estraverse@^4.1.1": + "integrity" "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + "version" "4.3.0" -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== +"estraverse@^5.1.0": + "integrity" "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" + "version" "5.2.0" -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +"estraverse@^5.2.0": + "integrity" "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" + "version" "5.2.0" -exec-sh@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" - integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== +"esutils@^2.0.2": + "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + "version" "2.0.3" + +"execall@^2.0.0": + "integrity" "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==" + "resolved" "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz" + "version" "2.0.0" dependencies: - merge "^1.2.0" + "clone-regexp" "^2.1.0" -execall@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45" - integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow== - dependencies: - clone-regexp "^2.1.0" +"extend@^3.0.0": + "integrity" "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "resolved" "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" + "version" "3.0.2" -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +"fast-deep-equal@^3.1.1": + "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + "version" "3.1.3" -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.1.1, fast-glob@^3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" - integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== +"fast-glob@^3.1.1", "fast-glob@^3.2.5": + "integrity" "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==" + "resolved" "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz" + "version" "3.2.5" dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" + "glob-parent" "^5.1.0" + "merge2" "^1.3.0" + "micromatch" "^4.0.2" + "picomatch" "^2.2.1" -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +"fast-json-stable-stringify@^2.0.0": + "integrity" "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "resolved" "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + "version" "2.1.0" -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +"fast-levenshtein@^2.0.6": + "integrity" "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "resolved" "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + "version" "2.0.6" -fastest-levenshtein@^1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" - integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== +"fastest-levenshtein@^1.0.12": + "integrity" "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" + "resolved" "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz" + "version" "1.0.12" -fastq@^1.6.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.11.0.tgz#bb9fb955a07130a918eb63c1f5161cc32a5d0858" - integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g== +"fastq@^1.6.0": + "integrity" "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==" + "resolved" "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz" + "version" "1.11.0" dependencies: - reusify "^1.0.4" + "reusify" "^1.0.4" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +"file-entry-cache@^6.0.1": + "integrity" "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==" + "resolved" "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + "version" "6.0.1" dependencies: - flat-cache "^3.0.4" + "flat-cache" "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +"fill-range@^7.0.1": + "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==" + "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + "version" "7.0.1" dependencies: - to-regex-range "^5.0.1" + "to-regex-range" "^5.0.1" -find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== +"find-up@^4.1.0": + "integrity" "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==" + "resolved" "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + "version" "4.1.0" dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" + "locate-path" "^5.0.0" + "path-exists" "^4.0.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== +"flat-cache@^3.0.4": + "integrity" "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==" + "resolved" "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + "version" "3.0.4" dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" + "flatted" "^3.1.0" + "rimraf" "^3.0.2" -flatted@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" - integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== +"flatted@^3.1.0": + "integrity" "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==" + "resolved" "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz" + "version" "3.1.1" -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= +"fs.realpath@^1.0.0": + "integrity" "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "version" "1.0.0" -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +"function-bind@^1.1.1": + "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" + "version" "1.1.1" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +"functional-red-black-tree@^1.0.1": + "integrity" "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + "resolved" "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + "version" "1.0.1" -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +"gensync@^1.0.0-beta.2": + "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + "version" "1.0.0-beta.2" -get-stdin@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" - integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== +"get-stdin@^8.0.0": + "integrity" "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==" + "resolved" "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz" + "version" "8.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== +"glob-parent@^5.0.0", "glob-parent@^5.1.0": + "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==" + "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + "version" "5.1.2" dependencies: - is-glob "^4.0.1" + "is-glob" "^4.0.1" -glob@^7.1.3: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== +"glob@^7.1.3": + "integrity" "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==" + "resolved" "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" + "version" "7.1.7" dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" + "fs.realpath" "^1.0.0" + "inflight" "^1.0.4" + "inherits" "2" + "minimatch" "^3.0.4" + "once" "^1.3.0" + "path-is-absolute" "^1.0.0" -global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== +"global-modules@^2.0.0": + "integrity" "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==" + "resolved" "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz" + "version" "2.0.0" dependencies: - global-prefix "^3.0.0" + "global-prefix" "^3.0.0" -global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== +"global-prefix@^3.0.0": + "integrity" "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==" + "resolved" "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz" + "version" "3.0.0" dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" + "ini" "^1.3.5" + "kind-of" "^6.0.2" + "which" "^1.3.1" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +"globals@^11.1.0": + "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + "version" "11.12.0" -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== +"globals@^12.1.0": + "integrity" "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==" + "resolved" "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz" + "version" "12.4.0" dependencies: - type-fest "^0.8.1" + "type-fest" "^0.8.1" -globals@^13.6.0: - version "13.8.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.8.0.tgz#3e20f504810ce87a8d72e55aecf8435b50f4c1b3" - integrity sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q== +"globals@^13.6.0": + "integrity" "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==" + "resolved" "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz" + "version" "13.8.0" dependencies: - type-fest "^0.20.2" + "type-fest" "^0.20.2" -globby@^11.0.3: - version "11.0.3" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb" - integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg== +"globby@^11.0.3": + "integrity" "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==" + "resolved" "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz" + "version" "11.0.3" dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" + "array-union" "^2.1.0" + "dir-glob" "^3.0.1" + "fast-glob" "^3.1.1" + "ignore" "^5.1.4" + "merge2" "^1.3.0" + "slash" "^3.0.0" -globjoin@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" - integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= +"globjoin@^0.1.4": + "integrity" "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=" + "resolved" "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz" + "version" "0.1.4" -gonzales-pe@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" - integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== +"gonzales-pe@^4.3.0": + "integrity" "sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==" + "resolved" "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz" + "version" "4.3.0" dependencies: - minimist "^1.2.5" + "minimist" "^1.2.5" -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== +"hard-rejection@^2.1.0": + "integrity" "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==" + "resolved" "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz" + "version" "2.1.0" -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +"has-flag@^3.0.0": + "integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + "version" "3.0.0" -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +"has-flag@^4.0.0": + "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + "version" "4.0.0" -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== +"has@^1.0.3": + "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==" + "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz" + "version" "1.0.3" dependencies: - function-bind "^1.1.1" + "function-bind" "^1.1.1" -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== +"hosted-git-info@^2.1.4": + "integrity" "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" + "resolved" "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" + "version" "2.8.9" -hosted-git-info@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" - integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg== +"hosted-git-info@^4.0.1": + "integrity" "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==" + "resolved" "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz" + "version" "4.0.2" dependencies: - lru-cache "^6.0.0" + "lru-cache" "^6.0.0" -html-tags@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" - integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== +"html-tags@^3.1.0": + "integrity" "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==" + "resolved" "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz" + "version" "3.1.0" -htmlparser2@^3.10.0: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== +"htmlparser2@^3.10.0": + "integrity" "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==" + "resolved" "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz" + "version" "3.10.1" dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" + "domelementtype" "^1.3.1" + "domhandler" "^2.3.0" + "domutils" "^1.5.1" + "entities" "^1.1.1" + "inherits" "^2.0.1" + "readable-stream" "^3.1.1" -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +"ignore@^4.0.6": + "integrity" "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" + "resolved" "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" + "version" "4.0.6" -ignore@^5.1.4, ignore@^5.1.8: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +"ignore@^5.1.4": + "integrity" "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" + "version" "5.1.8" -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== +"ignore@^5.1.8": + "integrity" "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" + "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" + "version" "5.1.8" + +"import-fresh@^3.0.0", "import-fresh@^3.2.1": + "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==" + "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + "version" "3.3.0" dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" + "parent-module" "^1.0.0" + "resolve-from" "^4.0.0" -import-lazy@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" - integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== +"import-lazy@^4.0.0": + "integrity" "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==" + "resolved" "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz" + "version" "4.0.0" -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +"imurmurhash@^0.1.4": + "integrity" "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "resolved" "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + "version" "0.1.4" -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +"indent-string@^4.0.0": + "integrity" "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + "resolved" "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + "version" "4.0.0" -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= +"inflight@^1.0.4": + "integrity" "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=" + "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + "version" "1.0.6" dependencies: - once "^1.3.0" - wrappy "1" + "once" "^1.3.0" + "wrappy" "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +"inherits@^2.0.1", "inherits@^2.0.3", "inherits@2": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" -ini@^1.3.5: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +"ini@^1.3.5": + "integrity" "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + "resolved" "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + "version" "1.3.8" -is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== +"is-alphabetical@^1.0.0": + "integrity" "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==" + "resolved" "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz" + "version" "1.0.4" -is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== +"is-alphanumerical@^1.0.0": + "integrity" "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==" + "resolved" "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz" + "version" "1.0.4" dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" + "is-alphabetical" "^1.0.0" + "is-decimal" "^1.0.0" -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +"is-arrayish@^0.2.1": + "integrity" "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "resolved" "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + "version" "0.2.1" -is-buffer@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== +"is-buffer@^2.0.0": + "integrity" "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + "resolved" "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz" + "version" "2.0.5" -is-core-module@^2.2.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" - integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== +"is-core-module@^2.2.0": + "integrity" "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==" + "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz" + "version" "2.4.0" dependencies: - has "^1.0.3" + "has" "^1.0.3" -is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== +"is-decimal@^1.0.0": + "integrity" "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==" + "resolved" "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz" + "version" "1.0.4" -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +"is-extglob@^2.1.1": + "integrity" "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + "version" "2.1.1" -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +"is-fullwidth-code-point@^3.0.0": + "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + "version" "3.0.0" -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +"is-glob@^4.0.0", "is-glob@^4.0.1": + "integrity" "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==" + "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz" + "version" "4.0.1" dependencies: - is-extglob "^2.1.1" + "is-extglob" "^2.1.1" -is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== +"is-hexadecimal@^1.0.0": + "integrity" "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" + "resolved" "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz" + "version" "1.0.4" -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +"is-number@^7.0.0": + "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + "version" "7.0.0" -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= +"is-plain-obj@^1.1.0": + "integrity" "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz" + "version" "1.1.0" -is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +"is-plain-obj@^2.0.0": + "integrity" "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==" + "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" + "version" "2.1.0" -is-regexp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" - integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== +"is-regexp@^2.0.0": + "integrity" "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==" + "resolved" "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz" + "version" "2.1.0" -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +"is-typedarray@^1.0.0": + "integrity" "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "resolved" "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + "version" "1.0.0" -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +"is-unicode-supported@^0.1.0": + "integrity" "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + "resolved" "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + "version" "0.1.0" -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +"isexe@^2.0.0": + "integrity" "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + "version" "2.0.0" -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== +"js-tokens@^4.0.0": + "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + "version" "4.0.0" -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== +"js-yaml@^3.13.1": + "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==" + "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + "version" "3.14.1" dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + "argparse" "^1.0.7" + "esprima" "^4.0.0" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +"jsesc@^2.5.1": + "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + "version" "2.5.2" -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +"json-parse-even-better-errors@^2.3.0": + "integrity" "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + "resolved" "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + "version" "2.3.1" -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +"json-schema-traverse@^0.4.1": + "integrity" "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + "version" "0.4.1" -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +"json-schema-traverse@^1.0.0": + "integrity" "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + "version" "1.0.0" -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +"json-stable-stringify-without-jsonify@^1.0.1": + "integrity" "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + "resolved" "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + "version" "1.0.1" -json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== +"json5@^2.1.2": + "integrity" "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==" + "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz" + "version" "2.2.0" dependencies: - minimist "^1.2.5" + "minimist" "^1.2.5" -kind-of@^6.0.2, kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +"kind-of@^6.0.2", "kind-of@^6.0.3": + "integrity" "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" + "version" "6.0.3" -known-css-properties@^0.21.0: - version "0.21.0" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.21.0.tgz#15fbd0bbb83447f3ce09d8af247ed47c68ede80d" - integrity sha512-sZLUnTqimCkvkgRS+kbPlYW5o8q5w1cu+uIisKpEWkj31I8mx8kNG162DwRav8Zirkva6N5uoFsm9kzK4mUXjw== +"known-css-properties@^0.21.0": + "integrity" "sha512-sZLUnTqimCkvkgRS+kbPlYW5o8q5w1cu+uIisKpEWkj31I8mx8kNG162DwRav8Zirkva6N5uoFsm9kzK4mUXjw==" + "resolved" "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.21.0.tgz" + "version" "0.21.0" -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== +"levn@^0.4.1": + "integrity" "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==" + "resolved" "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + "version" "0.4.1" dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" + "prelude-ls" "^1.2.1" + "type-check" "~0.4.0" -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +"lines-and-columns@^1.1.6": + "integrity" "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" + "resolved" "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz" + "version" "1.1.6" -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== +"locate-path@^5.0.0": + "integrity" "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==" + "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + "version" "5.0.0" dependencies: - p-locate "^4.1.0" + "p-locate" "^4.1.0" -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= +"lodash.clonedeep@^4.5.0": + "integrity" "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + "resolved" "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" + "version" "4.5.0" -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= +"lodash.truncate@^4.4.2": + "integrity" "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + "resolved" "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" + "version" "4.4.2" -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +"lodash@^4.17.14", "lodash@^4.17.15", "lodash@^4.17.21": + "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + "version" "4.17.21" -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== +"log-symbols@^4.1.0": + "integrity" "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==" + "resolved" "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + "version" "4.1.0" dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" + "chalk" "^4.1.0" + "is-unicode-supported" "^0.1.0" -longest-streak@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" - integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== +"longest-streak@^2.0.0": + "integrity" "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==" + "resolved" "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz" + "version" "2.0.4" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== +"lru-cache@^6.0.0": + "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==" + "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + "version" "6.0.0" dependencies: - yallist "^4.0.0" + "yallist" "^4.0.0" -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= +"map-obj@^1.0.0": + "integrity" "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + "resolved" "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" + "version" "1.0.1" -map-obj@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" - integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== +"map-obj@^4.0.0": + "integrity" "sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==" + "resolved" "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz" + "version" "4.2.1" -mathml-tag-names@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" - integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== +"mathml-tag-names@^2.1.3": + "integrity" "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==" + "resolved" "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz" + "version" "2.1.3" -mdast-util-from-markdown@^0.8.0: - version "0.8.5" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" - integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ== +"mdast-util-from-markdown@^0.8.0": + "integrity" "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==" + "resolved" "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz" + "version" "0.8.5" dependencies: "@types/mdast" "^3.0.0" - mdast-util-to-string "^2.0.0" - micromark "~2.11.0" - parse-entities "^2.0.0" - unist-util-stringify-position "^2.0.0" + "mdast-util-to-string" "^2.0.0" + "micromark" "~2.11.0" + "parse-entities" "^2.0.0" + "unist-util-stringify-position" "^2.0.0" -mdast-util-to-markdown@^0.6.0: - version "0.6.5" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz#b33f67ca820d69e6cc527a93d4039249b504bebe" - integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ== +"mdast-util-to-markdown@^0.6.0": + "integrity" "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==" + "resolved" "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz" + "version" "0.6.5" dependencies: "@types/unist" "^2.0.0" - longest-streak "^2.0.0" - mdast-util-to-string "^2.0.0" - parse-entities "^2.0.0" - repeat-string "^1.0.0" - zwitch "^1.0.0" + "longest-streak" "^2.0.0" + "mdast-util-to-string" "^2.0.0" + "parse-entities" "^2.0.0" + "repeat-string" "^1.0.0" + "zwitch" "^1.0.0" -mdast-util-to-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" - integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== +"mdast-util-to-string@^2.0.0": + "integrity" "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==" + "resolved" "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz" + "version" "2.0.0" -meow@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" - integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ== +"meow@^9.0.0": + "integrity" "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==" + "resolved" "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz" + "version" "9.0.0" dependencies: "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize "^1.2.0" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" + "camelcase-keys" "^6.2.2" + "decamelize" "^1.2.0" + "decamelize-keys" "^1.1.0" + "hard-rejection" "^2.1.0" + "minimist-options" "4.1.0" + "normalize-package-data" "^3.0.0" + "read-pkg-up" "^7.0.1" + "redent" "^3.0.0" + "trim-newlines" "^3.0.0" + "type-fest" "^0.18.0" + "yargs-parser" "^20.2.3" -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== +"merge@2.1.1": + "integrity" "sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w==" + "resolved" "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz" + "version" "2.1.1" -merge@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-2.1.1.tgz#59ef4bf7e0b3e879186436e8481c06a6c162ca98" - integrity sha512-jz+Cfrg9GWOZbQAnDQ4hlVnQky+341Yk5ru8bZSe6sIDTCIg8n9i/u7hSQGSVOF3C7lH6mGtqjkiT9G4wFLL0w== +"merge2@^1.3.0": + "integrity" "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + "resolved" "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + "version" "1.4.1" -merge@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" - integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== - -micromark@~2.11.0: - version "2.11.4" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" - integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== +"micromark@~2.11.0": + "integrity" "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==" + "resolved" "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz" + "version" "2.11.4" dependencies: - debug "^4.0.0" - parse-entities "^2.0.0" + "debug" "^4.0.0" + "parse-entities" "^2.0.0" -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== +"micromatch@^4.0.2", "micromatch@^4.0.4": + "integrity" "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==" + "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz" + "version" "4.0.4" dependencies: - braces "^3.0.1" - picomatch "^2.2.3" + "braces" "^3.0.1" + "picomatch" "^2.2.3" -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +"min-indent@^1.0.0": + "integrity" "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" + "resolved" "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" + "version" "1.0.1" -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +"minimatch@^3.0.4": + "integrity" "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==" + "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" + "version" "3.0.4" dependencies: - brace-expansion "^1.1.7" + "brace-expansion" "^1.1.7" -minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== +"minimist-options@4.1.0": + "integrity" "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==" + "resolved" "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz" + "version" "4.1.0" dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" + "arrify" "^1.0.1" + "is-plain-obj" "^1.1.0" + "kind-of" "^6.0.3" -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +"minimist@^1.1.0", "minimist@^1.2.5": + "integrity" "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz" + "version" "1.2.5" -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +"ms@2.1.2": + "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + "version" "2.1.2" -nanoid@^3.1.22: - version "3.1.23" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" - integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== +"nanoid@^3.1.22": + "integrity" "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==" + "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz" + "version" "3.1.23" -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +"natural-compare@^1.4.0": + "integrity" "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + "resolved" "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + "version" "1.4.0" -node-releases@^1.1.71: - version "1.1.72" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" - integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== +"node-releases@^1.1.71": + "integrity" "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==" + "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz" + "version" "1.1.72" -normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== +"normalize-package-data@^2.5.0": + "integrity" "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==" + "resolved" "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" + "version" "2.5.0" dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" + "hosted-git-info" "^2.1.4" + "resolve" "^1.10.0" + "semver" "2 || 3 || 4 || 5" + "validate-npm-package-license" "^3.0.1" -normalize-package-data@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699" - integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg== +"normalize-package-data@^3.0.0": + "integrity" "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==" + "resolved" "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz" + "version" "3.0.2" dependencies: - hosted-git-info "^4.0.1" - resolve "^1.20.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" + "hosted-git-info" "^4.0.1" + "resolve" "^1.20.0" + "semver" "^7.3.4" + "validate-npm-package-license" "^3.0.1" -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= +"normalize-range@^0.1.2": + "integrity" "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + "resolved" "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" + "version" "0.1.2" -normalize-selector@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" - integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM= +"normalize-selector@^0.2.0": + "integrity" "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=" + "resolved" "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz" + "version" "0.2.0" -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= +"num2fraction@^1.2.2": + "integrity" "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + "resolved" "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz" + "version" "1.2.2" -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= +"once@^1.3.0": + "integrity" "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=" + "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + "version" "1.4.0" dependencies: - wrappy "1" + "wrappy" "1" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +"optionator@^0.9.1": + "integrity" "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==" + "resolved" "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" + "version" "0.9.1" dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" + "deep-is" "^0.1.3" + "fast-levenshtein" "^2.0.6" + "levn" "^0.4.1" + "prelude-ls" "^1.2.1" + "type-check" "^0.4.0" + "word-wrap" "^1.2.3" -p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== +"p-limit@^2.2.0": + "integrity" "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==" + "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + "version" "2.3.0" dependencies: - p-try "^2.0.0" + "p-try" "^2.0.0" -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== +"p-locate@^4.1.0": + "integrity" "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==" + "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + "version" "4.1.0" dependencies: - p-limit "^2.2.0" + "p-limit" "^2.2.0" -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +"p-try@^2.0.0": + "integrity" "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + "resolved" "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + "version" "2.2.0" -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== +"parent-module@^1.0.0": + "integrity" "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==" + "resolved" "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + "version" "1.0.1" dependencies: - callsites "^3.0.0" + "callsites" "^3.0.0" -parse-entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" - integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== +"parse-entities@^2.0.0": + "integrity" "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==" + "resolved" "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz" + "version" "2.0.0" dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" + "character-entities" "^1.0.0" + "character-entities-legacy" "^1.0.0" + "character-reference-invalid" "^1.0.0" + "is-alphanumerical" "^1.0.0" + "is-decimal" "^1.0.0" + "is-hexadecimal" "^1.0.0" -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== +"parse-json@^5.0.0": + "integrity" "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==" + "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + "version" "5.2.0" dependencies: "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" + "error-ex" "^1.3.1" + "json-parse-even-better-errors" "^2.3.0" + "lines-and-columns" "^1.1.6" -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== +"path-exists@^4.0.0": + "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + "version" "4.0.0" -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +"path-is-absolute@^1.0.0": + "integrity" "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + "version" "1.0.1" -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +"path-key@^3.1.0": + "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + "version" "3.1.1" -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +"path-parse@^1.0.6": + "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + "version" "1.0.7" -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +"path-type@^4.0.0": + "integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + "resolved" "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + "version" "4.0.0" -picomatch@^2.2.1, picomatch@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.3.tgz#465547f359ccc206d3c48e46a1bcb89bf7ee619d" - integrity sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg== +"picocolors@^0.2.1": + "version" "0.2.1" -postcss-html@^0.36.0: - version "0.36.0" - resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204" - integrity sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw== +"picomatch@^2.2.1", "picomatch@^2.2.3": + "integrity" "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==" + "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz" + "version" "2.2.3" + +"postcss-html@^0.36.0": + "integrity" "sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==" + "resolved" "https://registry.npmjs.org/postcss-html/-/postcss-html-0.36.0.tgz" + "version" "0.36.0" dependencies: - htmlparser2 "^3.10.0" + "htmlparser2" "^3.10.0" -postcss-less@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-3.1.4.tgz#369f58642b5928ef898ffbc1a6e93c958304c5ad" - integrity sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA== +"postcss-less@^3.1.4": + "integrity" "sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==" + "resolved" "https://registry.npmjs.org/postcss-less/-/postcss-less-3.1.4.tgz" + "version" "3.1.4" dependencies: - postcss "^7.0.14" + "postcss" "^7.0.14" -postcss-media-query-parser@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" - integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= +"postcss-media-query-parser@^0.2.3": + "integrity" "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=" + "resolved" "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz" + "version" "0.2.3" -postcss-resolve-nested-selector@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= +"postcss-resolve-nested-selector@^0.1.1": + "integrity" "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=" + "resolved" "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz" + "version" "0.1.1" -postcss-safe-parser@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz#a6d4e48f0f37d9f7c11b2a581bf00f8ba4870b96" - integrity sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g== +"postcss-safe-parser@^4.0.2": + "integrity" "sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g==" + "resolved" "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz" + "version" "4.0.2" dependencies: - postcss "^7.0.26" + "postcss" "^7.0.26" -postcss-sass@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.4.4.tgz#91f0f3447b45ce373227a98b61f8d8f0785285a3" - integrity sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg== +"postcss-sass@^0.4.4": + "integrity" "sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg==" + "resolved" "https://registry.npmjs.org/postcss-sass/-/postcss-sass-0.4.4.tgz" + "version" "0.4.4" dependencies: - gonzales-pe "^4.3.0" - postcss "^7.0.21" + "gonzales-pe" "^4.3.0" + "postcss" "^7.0.21" -postcss-scss@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383" - integrity sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA== +"postcss-scss@^2.1.1": + "integrity" "sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==" + "resolved" "https://registry.npmjs.org/postcss-scss/-/postcss-scss-2.1.1.tgz" + "version" "2.1.1" dependencies: - postcss "^7.0.6" + "postcss" "^7.0.6" -postcss-selector-parser@^6.0.5: - version "6.0.6" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" - integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== +"postcss-selector-parser@^6.0.5": + "integrity" "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==" + "resolved" "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz" + "version" "6.0.6" dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" + "cssesc" "^3.0.0" + "util-deprecate" "^1.0.2" -postcss-sorting@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-5.0.1.tgz#10d5d0059eea8334dacc820c0121864035bc3f11" - integrity sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA== +"postcss-sorting@^5.0.1": + "integrity" "sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA==" + "resolved" "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-5.0.1.tgz" + "version" "5.0.1" dependencies: - lodash "^4.17.14" - postcss "^7.0.17" + "lodash" "^4.17.14" + "postcss" "^7.0.17" -postcss-syntax@^0.36.2: - version "0.36.2" - resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c" - integrity sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w== +"postcss-syntax@^0.36.2", "postcss-syntax@>=0.36.0", "postcss-syntax@>=0.36.2": + "integrity" "sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==" + "resolved" "https://registry.npmjs.org/postcss-syntax/-/postcss-syntax-0.36.2.tgz" + "version" "0.36.2" -postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== +"postcss-value-parser@^4.1.0": + "integrity" "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + "resolved" "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz" + "version" "4.1.0" -postcss@8.2.10: - version "8.2.10" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.10.tgz#ca7a042aa8aff494b334d0ff3e9e77079f6f702b" - integrity sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw== +"postcss@^7.0.14": + "version" "7.0.39" dependencies: - colorette "^1.2.2" - nanoid "^3.1.22" - source-map "^0.6.1" + "picocolors" "^0.2.1" + "source-map" "^0.6.1" -postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.31, postcss@^7.0.32, postcss@^7.0.35, postcss@^7.0.6: - version "7.0.35" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" - integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== +"postcss@^7.0.17": + "version" "7.0.39" dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" + "picocolors" "^0.2.1" + "source-map" "^0.6.1" -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== +"postcss@^7.0.2": + "version" "7.0.39" dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" + "picocolors" "^0.2.1" + "source-map" "^0.6.1" -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== +"postcss@^7.0.21": + "version" "7.0.39" + dependencies: + "picocolors" "^0.2.1" + "source-map" "^0.6.1" + +"postcss@^7.0.26": + "version" "7.0.39" + dependencies: + "picocolors" "^0.2.1" + "source-map" "^0.6.1" + +"postcss@^7.0.31": + "version" "7.0.39" + dependencies: + "picocolors" "^0.2.1" + "source-map" "^0.6.1" + +"postcss@^7.0.32": + "version" "7.0.39" + dependencies: + "picocolors" "^0.2.1" + "source-map" "^0.6.1" + +"postcss@^7.0.35", "postcss@>=5.0.0", "postcss@>=7.0.0": + "version" "7.0.39" + dependencies: + "picocolors" "^0.2.1" + "source-map" "^0.6.1" + +"postcss@^7.0.6": + "version" "7.0.39" + dependencies: + "picocolors" "^0.2.1" + "source-map" "^0.6.1" + +"postcss@8.2.10": + "integrity" "sha512-b/h7CPV7QEdrqIxtAf2j31U5ef05uBDuvoXv6L51Q4rcS1jdlXAVKJv+atCFdUXYl9dyTHGyoMzIepwowRJjFw==" + "resolved" "https://registry.npmjs.org/postcss/-/postcss-8.2.10.tgz" + "version" "8.2.10" + dependencies: + "colorette" "^1.2.2" + "nanoid" "^3.1.22" + "source-map" "^0.6.1" + +"prelude-ls@^1.2.1": + "integrity" "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" + "resolved" "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + "version" "1.2.1" + +"prettier@2.5.1": + "integrity" "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==" + "resolved" "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz" + "version" "2.5.1" + +"progress@^2.0.0": + "integrity" "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + "resolved" "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + "version" "2.0.3" + +"punycode@^2.1.0": + "integrity" "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "resolved" "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" + "version" "2.1.1" + +"queue-microtask@^1.2.2": + "integrity" "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + "resolved" "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + "version" "1.2.3" + +"quick-lru@^4.0.1": + "integrity" "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==" + "resolved" "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz" + "version" "4.0.1" + +"read-pkg-up@^7.0.1": + "integrity" "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==" + "resolved" "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" + "version" "7.0.1" + dependencies: + "find-up" "^4.1.0" + "read-pkg" "^5.2.0" + "type-fest" "^0.8.1" + +"read-pkg@^5.2.0": + "integrity" "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==" + "resolved" "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz" + "version" "5.2.0" dependencies: "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" + "normalize-package-data" "^2.5.0" + "parse-json" "^5.0.0" + "type-fest" "^0.6.0" -readable-stream@^3.1.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== +"readable-stream@^3.1.1": + "integrity" "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==" + "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + "version" "3.6.0" dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" + "inherits" "^2.0.3" + "string_decoder" "^1.1.1" + "util-deprecate" "^1.0.1" -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== +"redent@^3.0.0": + "integrity" "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==" + "resolved" "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" + "version" "3.0.0" dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" + "indent-string" "^4.0.0" + "strip-indent" "^3.0.0" -regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== +"regexpp@^3.1.0": + "integrity" "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==" + "resolved" "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz" + "version" "3.1.0" -remark-parse@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" - integrity sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw== +"remark-parse@^9.0.0": + "integrity" "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==" + "resolved" "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz" + "version" "9.0.0" dependencies: - mdast-util-from-markdown "^0.8.0" + "mdast-util-from-markdown" "^0.8.0" -remark-stringify@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-9.0.1.tgz#576d06e910548b0a7191a71f27b33f1218862894" - integrity sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg== +"remark-stringify@^9.0.0": + "integrity" "sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg==" + "resolved" "https://registry.npmjs.org/remark-stringify/-/remark-stringify-9.0.1.tgz" + "version" "9.0.1" dependencies: - mdast-util-to-markdown "^0.6.0" + "mdast-util-to-markdown" "^0.6.0" -remark@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/remark/-/remark-13.0.0.tgz#d15d9bf71a402f40287ebe36067b66d54868e425" - integrity sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA== +"remark@^13.0.0": + "integrity" "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==" + "resolved" "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz" + "version" "13.0.0" dependencies: - remark-parse "^9.0.0" - remark-stringify "^9.0.0" - unified "^9.1.0" + "remark-parse" "^9.0.0" + "remark-stringify" "^9.0.0" + "unified" "^9.1.0" -repeat-string@^1.0.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +"repeat-string@^1.0.0": + "integrity" "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "resolved" "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" + "version" "1.6.1" -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== +"require-from-string@^2.0.2": + "integrity" "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + "resolved" "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + "version" "2.0.2" -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +"resolve-from@^4.0.0": + "integrity" "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + "version" "4.0.0" -resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +"resolve-from@^5.0.0": + "integrity" "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + "version" "5.0.0" -resolve@^1.10.0, resolve@^1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== +"resolve@^1.10.0", "resolve@^1.20.0": + "integrity" "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==" + "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" + "version" "1.20.0" dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + "is-core-module" "^2.2.0" + "path-parse" "^1.0.6" -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +"reusify@^1.0.4": + "integrity" "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + "resolved" "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + "version" "1.0.4" -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== +"rimraf@^3.0.2": + "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==" + "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + "version" "3.0.2" dependencies: - glob "^7.1.3" + "glob" "^7.1.3" -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== +"run-parallel@^1.1.9": + "integrity" "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==" + "resolved" "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + "version" "1.2.0" dependencies: - queue-microtask "^1.2.2" + "queue-microtask" "^1.2.2" -safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +"safe-buffer@~5.1.1": + "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + "version" "5.1.2" -safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +"safe-buffer@~5.2.0": + "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + "version" "5.2.1" + +"semver@^6.3.0": + "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" + "version" "6.3.0" + +"semver@^7.2.1", "semver@^7.3.4": + "integrity" "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==" + "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" + "version" "7.3.5" + dependencies: + "lru-cache" "^6.0.0" "semver@2 || 3 || 4 || 5": - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" + "version" "5.7.1" -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -semver@^7.2.1, semver@^7.3.4: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== +"shebang-command@^2.0.0": + "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==" + "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + "version" "2.0.0" dependencies: - lru-cache "^6.0.0" + "shebang-regex" "^3.0.0" -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== +"shebang-regex@^3.0.0": + "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + "version" "3.0.0" + +"signal-exit@^3.0.2": + "integrity" "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz" + "version" "3.0.3" + +"slash@^3.0.0": + "integrity" "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + "resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + "version" "3.0.0" + +"slice-ansi@^4.0.0": + "integrity" "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==" + "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" + "version" "4.0.0" dependencies: - shebang-regex "^3.0.0" + "ansi-styles" "^4.0.0" + "astral-regex" "^2.0.0" + "is-fullwidth-code-point" "^3.0.0" -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +"source-map@^0.5.0": + "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" + "version" "0.5.7" -signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +"source-map@^0.6.1": + "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + "version" "0.6.1" -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== +"spdx-correct@^3.0.0": + "integrity" "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==" + "resolved" "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz" + "version" "3.1.1" dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" + "spdx-expression-parse" "^3.0.0" + "spdx-license-ids" "^3.0.0" -source-map@^0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= +"spdx-exceptions@^2.1.0": + "integrity" "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + "resolved" "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" + "version" "2.3.0" -source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== +"spdx-expression-parse@^3.0.0": + "integrity" "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==" + "resolved" "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" + "version" "3.0.1" dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" + "spdx-exceptions" "^2.1.0" + "spdx-license-ids" "^3.0.0" -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== +"spdx-license-ids@^3.0.0": + "integrity" "sha512-NDgA96EnaLSvtbM7trJj+t1LUR3pirkDCcz9nOUlPb5DMBGsH7oES6C3hs3j7R9oHEa1EMvReS/BUAIT5Tcr0g==" + "resolved" "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.8.tgz" + "version" "3.0.8" -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== +"specificity@^0.4.1": + "integrity" "sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==" + "resolved" "https://registry.npmjs.org/specificity/-/specificity-0.4.1.tgz" + "version" "0.4.1" + +"sprintf-js@~1.0.2": + "integrity" "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + "version" "1.0.3" + +"string_decoder@^1.1.1": + "integrity" "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==" + "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + "version" "1.3.0" dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" + "safe-buffer" "~5.2.0" -spdx-license-ids@^3.0.0: - version "3.0.8" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.8.tgz#eb1e97ad99b11bf3f82a3b71a0472dd9a00f2ecf" - integrity sha512-NDgA96EnaLSvtbM7trJj+t1LUR3pirkDCcz9nOUlPb5DMBGsH7oES6C3hs3j7R9oHEa1EMvReS/BUAIT5Tcr0g== - -specificity@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" - integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^4.2.0, string-width@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== +"string-width@^4.2.0", "string-width@^4.2.2": + "integrity" "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==" + "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz" + "version" "4.2.2" dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + "emoji-regex" "^8.0.0" + "is-fullwidth-code-point" "^3.0.0" + "strip-ansi" "^6.0.0" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== +"strip-ansi@^6.0.0": + "integrity" "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==" + "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" + "version" "6.0.0" dependencies: - safe-buffer "~5.2.0" + "ansi-regex" "^5.0.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +"strip-indent@^3.0.0": + "integrity" "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==" + "resolved" "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" + "version" "3.0.0" dependencies: - ansi-regex "^5.0.0" + "min-indent" "^1.0.0" -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== +"strip-json-comments@^3.1.0", "strip-json-comments@^3.1.1": + "integrity" "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + "resolved" "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + "version" "3.1.1" + +"style-search@^0.1.0": + "integrity" "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=" + "resolved" "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz" + "version" "0.1.0" + +"stylelint-config-recommended@^4.0.0": + "integrity" "sha512-sgna89Ng+25Hr9kmmaIxpGWt2LStVm1xf1807PdcWasiPDaOTkOHRL61sINw0twky7QMzafCGToGDnHT/kTHtQ==" + "resolved" "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-4.0.0.tgz" + "version" "4.0.0" + +"stylelint-config-standard@^21.0.0": + "integrity" "sha512-Yf6mx5oYEbQQJxWuW7X3t1gcxqbUx52qC9SMS3saC2ruOVYEyqmr5zSW6k3wXflDjjFrPhar3kp68ugRopmlzg==" + "resolved" "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-21.0.0.tgz" + "version" "21.0.0" dependencies: - min-indent "^1.0.0" + "stylelint-config-recommended" "^4.0.0" -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -style-search@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" - integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= - -stylelint-config-recommended@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-4.0.0.tgz#665a0034065e6704d5032ba51bf4efa37d328ef9" - integrity sha512-sgna89Ng+25Hr9kmmaIxpGWt2LStVm1xf1807PdcWasiPDaOTkOHRL61sINw0twky7QMzafCGToGDnHT/kTHtQ== - -stylelint-config-standard@^21.0.0: - version "21.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-21.0.0.tgz#4942cfa27301eb6702fa8fc46a44da35d1a5cfd7" - integrity sha512-Yf6mx5oYEbQQJxWuW7X3t1gcxqbUx52qC9SMS3saC2ruOVYEyqmr5zSW6k3wXflDjjFrPhar3kp68ugRopmlzg== +"stylelint-order@^4.1.0": + "integrity" "sha512-sVTikaDvMqg2aJjh4r48jsdfmqLT+nqB1MOsaBnvM3OwLx4S+WXcsxsgk5w18h/OZoxZCxuyXMh61iBHcj9Qiw==" + "resolved" "https://registry.npmjs.org/stylelint-order/-/stylelint-order-4.1.0.tgz" + "version" "4.1.0" dependencies: - stylelint-config-recommended "^4.0.0" + "lodash" "^4.17.15" + "postcss" "^7.0.31" + "postcss-sorting" "^5.0.1" -stylelint-order@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-4.1.0.tgz#692d05b7d0c235ac66fcf5ea1d9e5f08a76747f6" - integrity sha512-sVTikaDvMqg2aJjh4r48jsdfmqLT+nqB1MOsaBnvM3OwLx4S+WXcsxsgk5w18h/OZoxZCxuyXMh61iBHcj9Qiw== - dependencies: - lodash "^4.17.15" - postcss "^7.0.31" - postcss-sorting "^5.0.1" - -stylelint@^13.12.0: - version "13.13.1" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.13.1.tgz#fca9c9f5de7990ab26a00f167b8978f083a18f3c" - integrity sha512-Mv+BQr5XTUrKqAXmpqm6Ddli6Ief+AiPZkRsIrAoUKFuq/ElkUh9ZMYxXD0iQNZ5ADghZKLOWz1h7hTClB7zgQ== +"stylelint@^10.0.1 || ^11.0.0 || ^12.0.0 || ^13.0.0", "stylelint@^13.12.0": + "integrity" "sha512-Mv+BQr5XTUrKqAXmpqm6Ddli6Ief+AiPZkRsIrAoUKFuq/ElkUh9ZMYxXD0iQNZ5ADghZKLOWz1h7hTClB7zgQ==" + "resolved" "https://registry.npmjs.org/stylelint/-/stylelint-13.13.1.tgz" + "version" "13.13.1" dependencies: "@stylelint/postcss-css-in-js" "^0.37.2" "@stylelint/postcss-markdown" "^0.36.2" - autoprefixer "^9.8.6" - balanced-match "^2.0.0" - chalk "^4.1.1" - cosmiconfig "^7.0.0" - debug "^4.3.1" - execall "^2.0.0" - fast-glob "^3.2.5" - fastest-levenshtein "^1.0.12" - file-entry-cache "^6.0.1" - get-stdin "^8.0.0" - global-modules "^2.0.0" - globby "^11.0.3" - globjoin "^0.1.4" - html-tags "^3.1.0" - ignore "^5.1.8" - import-lazy "^4.0.0" - imurmurhash "^0.1.4" - known-css-properties "^0.21.0" - lodash "^4.17.21" - log-symbols "^4.1.0" - mathml-tag-names "^2.1.3" - meow "^9.0.0" - micromatch "^4.0.4" - normalize-selector "^0.2.0" - postcss "^7.0.35" - postcss-html "^0.36.0" - postcss-less "^3.1.4" - postcss-media-query-parser "^0.2.3" - postcss-resolve-nested-selector "^0.1.1" - postcss-safe-parser "^4.0.2" - postcss-sass "^0.4.4" - postcss-scss "^2.1.1" - postcss-selector-parser "^6.0.5" - postcss-syntax "^0.36.2" - postcss-value-parser "^4.1.0" - resolve-from "^5.0.0" - slash "^3.0.0" - specificity "^0.4.1" - string-width "^4.2.2" - strip-ansi "^6.0.0" - style-search "^0.1.0" - sugarss "^2.0.0" - svg-tags "^1.0.0" - table "^6.6.0" - v8-compile-cache "^2.3.0" - write-file-atomic "^3.0.3" + "autoprefixer" "^9.8.6" + "balanced-match" "^2.0.0" + "chalk" "^4.1.1" + "cosmiconfig" "^7.0.0" + "debug" "^4.3.1" + "execall" "^2.0.0" + "fast-glob" "^3.2.5" + "fastest-levenshtein" "^1.0.12" + "file-entry-cache" "^6.0.1" + "get-stdin" "^8.0.0" + "global-modules" "^2.0.0" + "globby" "^11.0.3" + "globjoin" "^0.1.4" + "html-tags" "^3.1.0" + "ignore" "^5.1.8" + "import-lazy" "^4.0.0" + "imurmurhash" "^0.1.4" + "known-css-properties" "^0.21.0" + "lodash" "^4.17.21" + "log-symbols" "^4.1.0" + "mathml-tag-names" "^2.1.3" + "meow" "^9.0.0" + "micromatch" "^4.0.4" + "normalize-selector" "^0.2.0" + "postcss" "^7.0.35" + "postcss-html" "^0.36.0" + "postcss-less" "^3.1.4" + "postcss-media-query-parser" "^0.2.3" + "postcss-resolve-nested-selector" "^0.1.1" + "postcss-safe-parser" "^4.0.2" + "postcss-sass" "^0.4.4" + "postcss-scss" "^2.1.1" + "postcss-selector-parser" "^6.0.5" + "postcss-syntax" "^0.36.2" + "postcss-value-parser" "^4.1.0" + "resolve-from" "^5.0.0" + "slash" "^3.0.0" + "specificity" "^0.4.1" + "string-width" "^4.2.2" + "strip-ansi" "^6.0.0" + "style-search" "^0.1.0" + "sugarss" "^2.0.0" + "svg-tags" "^1.0.0" + "table" "^6.6.0" + "v8-compile-cache" "^2.3.0" + "write-file-atomic" "^3.0.3" -sugarss@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" - integrity sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ== +"sugarss@^2.0.0": + "integrity" "sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==" + "resolved" "https://registry.npmjs.org/sugarss/-/sugarss-2.0.0.tgz" + "version" "2.0.0" dependencies: - postcss "^7.0.2" + "postcss" "^7.0.2" -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== +"supports-color@^5.3.0": + "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + "version" "5.5.0" dependencies: - has-flag "^3.0.0" + "has-flag" "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== +"supports-color@^7.1.0": + "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==" + "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + "version" "7.2.0" dependencies: - has-flag "^3.0.0" + "has-flag" "^4.0.0" -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== +"svg-tags@^1.0.0": + "integrity" "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=" + "resolved" "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz" + "version" "1.0.0" + +"table@^6.0.4", "table@^6.6.0": + "integrity" "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==" + "resolved" "https://registry.npmjs.org/table/-/table-6.7.1.tgz" + "version" "6.7.1" dependencies: - has-flag "^4.0.0" + "ajv" "^8.0.1" + "lodash.clonedeep" "^4.5.0" + "lodash.truncate" "^4.4.2" + "slice-ansi" "^4.0.0" + "string-width" "^4.2.0" + "strip-ansi" "^6.0.0" -svg-tags@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" - integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= +"text-table@^0.2.0": + "integrity" "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + "resolved" "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + "version" "0.2.0" -table@^6.0.4, table@^6.6.0: - version "6.7.1" - resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" - integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== +"to-fast-properties@^2.0.0": + "integrity" "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + "version" "2.0.0" + +"to-regex-range@^5.0.1": + "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==" + "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + "version" "5.0.1" dependencies: - ajv "^8.0.1" - lodash.clonedeep "^4.5.0" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" + "is-number" "^7.0.0" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +"trim-newlines@^3.0.0": + "integrity" "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==" + "resolved" "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz" + "version" "3.0.1" -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +"trough@^1.0.0": + "integrity" "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" + "resolved" "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz" + "version" "1.0.5" -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== +"type-check@^0.4.0", "type-check@~0.4.0": + "integrity" "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==" + "resolved" "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + "version" "0.4.0" dependencies: - is-number "^7.0.0" + "prelude-ls" "^1.2.1" -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +"type-fest@^0.18.0": + "integrity" "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz" + "version" "0.18.1" -trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +"type-fest@^0.20.2": + "integrity" "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + "version" "0.20.2" -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== +"type-fest@^0.6.0": + "integrity" "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" + "version" "0.6.0" + +"type-fest@^0.8.1": + "integrity" "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==" + "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" + "version" "0.8.1" + +"typedarray-to-buffer@^3.1.5": + "integrity" "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==" + "resolved" "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" + "version" "3.1.5" dependencies: - prelude-ls "^1.2.1" + "is-typedarray" "^1.0.0" -type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== +"unified@^9.1.0": + "integrity" "sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==" + "resolved" "https://registry.npmjs.org/unified/-/unified-9.2.1.tgz" + "version" "9.2.1" dependencies: - is-typedarray "^1.0.0" + "bail" "^1.0.0" + "extend" "^3.0.0" + "is-buffer" "^2.0.0" + "is-plain-obj" "^2.0.0" + "trough" "^1.0.0" + "vfile" "^4.0.0" -unified@^9.1.0: - version "9.2.1" - resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.1.tgz#ae18d5674c114021bfdbdf73865ca60f410215a3" - integrity sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA== +"unist-util-find-all-after@^3.0.2": + "integrity" "sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==" + "resolved" "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz" + "version" "3.0.2" dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" + "unist-util-is" "^4.0.0" -unist-util-find-all-after@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz#fdfecd14c5b7aea5e9ef38d5e0d5f774eeb561f6" - integrity sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ== - dependencies: - unist-util-is "^4.0.0" +"unist-util-is@^4.0.0": + "integrity" "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==" + "resolved" "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz" + "version" "4.1.0" -unist-util-is@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" - integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== - -unist-util-stringify-position@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" - integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== +"unist-util-stringify-position@^2.0.0": + "integrity" "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==" + "resolved" "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz" + "version" "2.0.3" dependencies: "@types/unist" "^2.0.2" -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== +"uri-js@^4.2.2": + "integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==" + "resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + "version" "4.4.1" dependencies: - punycode "^2.1.0" + "punycode" "^2.1.0" -util-deprecate@^1.0.1, util-deprecate@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +"util-deprecate@^1.0.1", "util-deprecate@^1.0.2": + "integrity" "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "version" "1.0.2" -v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +"v8-compile-cache@^2.0.3", "v8-compile-cache@^2.3.0": + "integrity" "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" + "resolved" "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" + "version" "2.3.0" -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== +"validate-npm-package-license@^3.0.1": + "integrity" "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==" + "resolved" "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" + "version" "3.0.4" dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" + "spdx-correct" "^3.0.0" + "spdx-expression-parse" "^3.0.0" -vfile-message@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" - integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== +"vfile-message@^2.0.0": + "integrity" "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==" + "resolved" "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz" + "version" "2.0.4" dependencies: "@types/unist" "^2.0.0" - unist-util-stringify-position "^2.0.0" + "unist-util-stringify-position" "^2.0.0" -vfile@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" - integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== +"vfile@^4.0.0": + "integrity" "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==" + "resolved" "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz" + "version" "4.2.1" dependencies: "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^2.0.0" - vfile-message "^2.0.0" + "is-buffer" "^2.0.0" + "unist-util-stringify-position" "^2.0.0" + "vfile-message" "^2.0.0" -watch@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" - integrity sha1-NApxe952Vyb6CqB9ch4BR6VR3ww= +"watch@^0.13.0": + "integrity" "sha1-/MbSs/DoxzSC61Qjmhn9W8+adTw=" + "resolved" "https://registry.npmjs.org/watch/-/watch-0.13.0.tgz" + "version" "0.13.0" dependencies: - exec-sh "^0.2.0" - minimist "^1.2.0" + "minimist" "^1.1.0" -which@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== +"which@^1.3.1": + "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==" + "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + "version" "1.3.1" dependencies: - isexe "^2.0.0" + "isexe" "^2.0.0" -which@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== +"which@^2.0.1": + "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==" + "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + "version" "2.0.2" dependencies: - isexe "^2.0.0" + "isexe" "^2.0.0" -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +"word-wrap@^1.2.3": + "integrity" "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" + "resolved" "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" + "version" "1.2.3" -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +"wrappy@1": + "integrity" "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "version" "1.0.2" -write-file-atomic@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== +"write-file-atomic@^3.0.3": + "integrity" "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==" + "resolved" "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" + "version" "3.0.3" dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" + "imurmurhash" "^0.1.4" + "is-typedarray" "^1.0.0" + "signal-exit" "^3.0.2" + "typedarray-to-buffer" "^3.1.5" -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +"yallist@^4.0.0": + "integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + "version" "4.0.0" -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +"yaml@^1.10.0": + "integrity" "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + "resolved" "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" + "version" "1.10.2" -yargs-parser@^20.2.3: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== +"yargs-parser@^20.2.3": + "integrity" "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==" + "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz" + "version" "20.2.7" -zwitch@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" - integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== +"zwitch@^1.0.0": + "integrity" "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==" + "resolved" "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz" + "version" "1.0.5" From 2fa1aa4cc7f4b300fd96908c2b229230926589d9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 16 Dec 2021 10:43:24 -0800 Subject: [PATCH 035/256] Adds bw-dev command --- bw-dev | 3 +++ complete_bwdev.sh | 1 + 2 files changed, 4 insertions(+) diff --git a/bw-dev b/bw-dev index cfe8747f..a76bb828 100755 --- a/bw-dev +++ b/bw-dev @@ -130,6 +130,9 @@ case "$CMD" in black) makeitblack ;; + prettier) + npx prettier --write bookwyrm/static/js/*.js + ;; populate_streams) runweb python manage.py populate_streams $@ ;; diff --git a/complete_bwdev.sh b/complete_bwdev.sh index b9cd7420..e7a036cc 100644 --- a/complete_bwdev.sh +++ b/complete_bwdev.sh @@ -20,6 +20,7 @@ update_locales build clean black +prettier populate_streams populate_suggestions generate_thumbnails From 34a16667d8384ffc87fdf12ee89cc8056458388c Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 16 Dec 2021 10:47:22 -0800 Subject: [PATCH 036/256] Adds github workflow --- .github/workflows/prettier.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/prettier.yaml diff --git a/.github/workflows/prettier.yaml b/.github/workflows/prettier.yaml new file mode 100644 index 00000000..80696060 --- /dev/null +++ b/.github/workflows/prettier.yaml @@ -0,0 +1,24 @@ +# @url https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions +name: JavaScript Prettier (run ./bw-dev prettier to fix) + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + lint: + name: Lint with Prettier + runs-on: ubuntu-20.04 + + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it. + - uses: actions/checkout@v2 + + - name: Install modules + run: npm install . + + # See .stylelintignore for files that are not linted. + - name: Run Prettier + run: npx prettier --check bookwyrm/static/js/*.js From 2b6c9d9d31a889947f7ae19ea535c868558a70ce Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Thu, 16 Dec 2021 10:53:38 -0800 Subject: [PATCH 037/256] Runs prettier --- bookwyrm/static/js/block_href.js | 10 +- bookwyrm/static/js/bookwyrm.js | 255 +++++++++++++---------------- bookwyrm/static/js/check_all.js | 15 +- bookwyrm/static/js/localstorage.js | 19 ++- bookwyrm/static/js/status_cache.js | 113 +++++++------ 5 files changed, 199 insertions(+), 213 deletions(-) diff --git a/bookwyrm/static/js/block_href.js b/bookwyrm/static/js/block_href.js index fc20a6ab..ac10b6de 100644 --- a/bookwyrm/static/js/block_href.js +++ b/bookwyrm/static/js/block_href.js @@ -1,9 +1,10 @@ /* exported BlockHref */ -let BlockHref = new class { +let BlockHref = new (class { constructor() { - document.querySelectorAll('[data-href]') - .forEach(t => t.addEventListener('click', this.followLink.bind(this))); + document + .querySelectorAll("[data-href]") + .forEach((t) => t.addEventListener("click", this.followLink.bind(this))); } /** @@ -17,5 +18,4 @@ let BlockHref = new class { window.location.href = url; } -}(); - +})(); diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index 2b78bf51..ebdcbca0 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -1,7 +1,7 @@ /* exported BookWyrm */ /* globals TabGroup */ -let BookWyrm = new class { +let BookWyrm = new (class { constructor() { this.MAX_FILE_SIZE_BYTES = 10 * 1000000; this.initOnDOMLoaded(); @@ -10,48 +10,33 @@ let BookWyrm = new class { } initEventListeners() { - document.querySelectorAll('[data-controls]') - .forEach(button => button.addEventListener( - 'click', - this.toggleAction.bind(this)) - ); + document + .querySelectorAll("[data-controls]") + .forEach((button) => button.addEventListener("click", this.toggleAction.bind(this))); - document.querySelectorAll('.interaction') - .forEach(button => button.addEventListener( - 'submit', - this.interact.bind(this)) - ); + document + .querySelectorAll(".interaction") + .forEach((button) => button.addEventListener("submit", this.interact.bind(this))); - document.querySelectorAll('.hidden-form input') - .forEach(button => button.addEventListener( - 'change', - this.revealForm.bind(this)) - ); + document + .querySelectorAll(".hidden-form input") + .forEach((button) => button.addEventListener("change", this.revealForm.bind(this))); - document.querySelectorAll('[data-hides]') - .forEach(button => button.addEventListener( - 'change', - this.hideForm.bind(this)) - ); + document + .querySelectorAll("[data-hides]") + .forEach((button) => button.addEventListener("change", this.hideForm.bind(this))); - document.querySelectorAll('[data-back]') - .forEach(button => button.addEventListener( - 'click', - this.back) - ); + document + .querySelectorAll("[data-back]") + .forEach((button) => button.addEventListener("click", this.back)); - document.querySelectorAll('input[type="file"]') - .forEach(node => node.addEventListener( - 'change', - this.disableIfTooLarge.bind(this) - )); - - document.querySelectorAll('[data-duplicate]') - .forEach(node => node.addEventListener( - 'click', - this.duplicateInput.bind(this) - - )) + document + .querySelectorAll('input[type="file"]') + .forEach((node) => node.addEventListener("change", this.disableIfTooLarge.bind(this))); + + document + .querySelectorAll("[data-duplicate]") + .forEach((node) => node.addEventListener("click", this.duplicateInput.bind(this))); } /** @@ -60,15 +45,12 @@ let BookWyrm = new class { initOnDOMLoaded() { const bookwyrm = this; - window.addEventListener('DOMContentLoaded', function() { - document.querySelectorAll('.tab-group') - .forEach(tabs => new TabGroup(tabs)); - document.querySelectorAll('input[type="file"]').forEach( - bookwyrm.disableIfTooLarge.bind(bookwyrm) - ); - document.querySelectorAll('[data-copytext]').forEach( - bookwyrm.copyText.bind(bookwyrm) - ); + window.addEventListener("DOMContentLoaded", function () { + document.querySelectorAll(".tab-group").forEach((tabs) => new TabGroup(tabs)); + document + .querySelectorAll('input[type="file"]') + .forEach(bookwyrm.disableIfTooLarge.bind(bookwyrm)); + document.querySelectorAll("[data-copytext]").forEach(bookwyrm.copyText.bind(bookwyrm)); }); } @@ -77,8 +59,7 @@ let BookWyrm = new class { */ initReccuringTasks() { // Polling - document.querySelectorAll('[data-poll]') - .forEach(liveArea => this.polling(liveArea)); + document.querySelectorAll("[data-poll]").forEach((liveArea) => this.polling(liveArea)); } /** @@ -104,15 +85,19 @@ let BookWyrm = new class { const bookwyrm = this; delay = delay || 10000; - delay += (Math.random() * 1000); + delay += Math.random() * 1000; - setTimeout(function() { - fetch('/api/updates/' + counter.dataset.poll) - .then(response => response.json()) - .then(data => bookwyrm.updateCountElement(counter, data)); + setTimeout( + function () { + fetch("/api/updates/" + counter.dataset.poll) + .then((response) => response.json()) + .then((data) => bookwyrm.updateCountElement(counter, data)); - bookwyrm.polling(counter, delay * 1.25); - }, delay, counter); + bookwyrm.polling(counter, delay * 1.25); + }, + delay, + counter + ); } /** @@ -127,60 +112,56 @@ let BookWyrm = new class { const count_by_type = data.count_by_type; const currentCount = counter.innerText; const hasMentions = data.has_mentions; - const allowedStatusTypesEl = document.getElementById('unread-notifications-wrapper'); + const allowedStatusTypesEl = document.getElementById("unread-notifications-wrapper"); // If we're on the right counter element - if (counter.closest('[data-poll-wrapper]').contains(allowedStatusTypesEl)) { + if (counter.closest("[data-poll-wrapper]").contains(allowedStatusTypesEl)) { const allowedStatusTypes = JSON.parse(allowedStatusTypesEl.textContent); // For keys in common between allowedStatusTypes and count_by_type // This concerns 'review', 'quotation', 'comment' - count = allowedStatusTypes.reduce(function(prev, currentKey) { + count = allowedStatusTypes.reduce(function (prev, currentKey) { const currentValue = count_by_type[currentKey] | 0; return prev + currentValue; }, 0); // Add all the "other" in count_by_type if 'everything' is allowed - if (allowedStatusTypes.includes('everything')) { + if (allowedStatusTypes.includes("everything")) { // Clone count_by_type with 0 for reviews/quotations/comments - const count_by_everything_else = Object.assign( - {}, - count_by_type, - {review: 0, quotation: 0, comment: 0} - ); + const count_by_everything_else = Object.assign({}, count_by_type, { + review: 0, + quotation: 0, + comment: 0, + }); - count = Object.keys(count_by_everything_else).reduce( - function(prev, currentKey) { - const currentValue = - count_by_everything_else[currentKey] | 0 + count = Object.keys(count_by_everything_else).reduce(function (prev, currentKey) { + const currentValue = count_by_everything_else[currentKey] | 0; - return prev + currentValue; - }, - count - ); + return prev + currentValue; + }, count); } } if (count != currentCount) { - this.addRemoveClass(counter.closest('[data-poll-wrapper]'), 'is-hidden', count < 1); + this.addRemoveClass(counter.closest("[data-poll-wrapper]"), "is-hidden", count < 1); counter.innerText = count; - this.addRemoveClass(counter.closest('[data-poll-wrapper]'), 'is-danger', hasMentions); + this.addRemoveClass(counter.closest("[data-poll-wrapper]"), "is-danger", hasMentions); } } /** * Show form. - * + * * @param {Event} event * @return {undefined} */ revealForm(event) { let trigger = event.currentTarget; - let hidden = trigger.closest('.hidden-form').querySelectorAll('.is-hidden')[0]; + let hidden = trigger.closest(".hidden-form").querySelectorAll(".is-hidden")[0]; if (hidden) { - this.addRemoveClass(hidden, 'is-hidden', !hidden); + this.addRemoveClass(hidden, "is-hidden", !hidden); } } @@ -192,10 +173,10 @@ let BookWyrm = new class { */ hideForm(event) { let trigger = event.currentTarget; - let targetId = trigger.dataset.hides - let visible = document.getElementById(targetId) + let targetId = trigger.dataset.hides; + let visible = document.getElementById(targetId); - this.addRemoveClass(visible, 'is-hidden', true); + this.addRemoveClass(visible, "is-hidden", true); } /** @@ -210,31 +191,34 @@ let BookWyrm = new class { if (!trigger.dataset.allowDefault || event.currentTarget == event.target) { event.preventDefault(); } - let pressed = trigger.getAttribute('aria-pressed') === 'false'; + let pressed = trigger.getAttribute("aria-pressed") === "false"; let targetId = trigger.dataset.controls; // Toggle pressed status on all triggers controlling the same target. - document.querySelectorAll('[data-controls="' + targetId + '"]') - .forEach(otherTrigger => otherTrigger.setAttribute( - 'aria-pressed', - otherTrigger.getAttribute('aria-pressed') === 'false' - )); + document + .querySelectorAll('[data-controls="' + targetId + '"]') + .forEach((otherTrigger) => + otherTrigger.setAttribute( + "aria-pressed", + otherTrigger.getAttribute("aria-pressed") === "false" + ) + ); // @todo Find a better way to handle the exception. - if (targetId && ! trigger.classList.contains('pulldown-menu')) { + if (targetId && !trigger.classList.contains("pulldown-menu")) { let target = document.getElementById(targetId); - this.addRemoveClass(target, 'is-hidden', !pressed); - this.addRemoveClass(target, 'is-active', pressed); + this.addRemoveClass(target, "is-hidden", !pressed); + this.addRemoveClass(target, "is-active", pressed); } // Show/hide pulldown-menus. - if (trigger.classList.contains('pulldown-menu')) { + if (trigger.classList.contains("pulldown-menu")) { this.toggleMenu(trigger, targetId); } // Show/hide container. - let container = document.getElementById('hide_' + targetId); + let container = document.getElementById("hide_" + targetId); if (container) { this.toggleContainer(container, pressed); @@ -271,14 +255,14 @@ let BookWyrm = new class { * @return {undefined} */ toggleMenu(trigger, targetId) { - let expanded = trigger.getAttribute('aria-expanded') == 'false'; + let expanded = trigger.getAttribute("aria-expanded") == "false"; - trigger.setAttribute('aria-expanded', expanded); + trigger.setAttribute("aria-expanded", expanded); if (targetId) { let target = document.getElementById(targetId); - this.addRemoveClass(target, 'is-active', expanded); + this.addRemoveClass(target, "is-active", expanded); } } @@ -290,7 +274,7 @@ let BookWyrm = new class { * @return {undefined} */ toggleContainer(container, pressed) { - this.addRemoveClass(container, 'is-hidden', pressed); + this.addRemoveClass(container, "is-hidden", pressed); } /** @@ -327,7 +311,7 @@ let BookWyrm = new class { node.focus(); - setTimeout(function() { + setTimeout(function () { node.selectionStart = node.selectionEnd = 10000; }, 0); } @@ -347,15 +331,17 @@ let BookWyrm = new class { const relatedforms = document.querySelectorAll(`.${form.dataset.id}`); // Toggle class on all related forms. - relatedforms.forEach(relatedForm => bookwyrm.addRemoveClass( - relatedForm, - 'is-hidden', - relatedForm.className.indexOf('is-hidden') == -1 - )); + relatedforms.forEach((relatedForm) => + bookwyrm.addRemoveClass( + relatedForm, + "is-hidden", + relatedForm.className.indexOf("is-hidden") == -1 + ) + ); - this.ajaxPost(form).catch(error => { + this.ajaxPost(form).catch((error) => { // @todo Display a notification in the UI instead. - console.warn('Request failed:', error); + console.warn("Request failed:", error); }); } @@ -367,11 +353,11 @@ let BookWyrm = new class { */ ajaxPost(form) { return fetch(form.action, { - method : "POST", + method: "POST", body: new FormData(form), headers: { - 'Accept': 'application/json', - } + Accept: "application/json", + }, }); } @@ -396,21 +382,16 @@ let BookWyrm = new class { const element = eventOrElement.currentTarget || eventOrElement; const submits = element.form.querySelectorAll('[type="submit"]'); - const warns = element.parentElement.querySelectorAll('.file-too-big'); - const isTooBig = element.files && - element.files[0] && - element.files[0].size > MAX_FILE_SIZE_BYTES; + const warns = element.parentElement.querySelectorAll(".file-too-big"); + const isTooBig = + element.files && element.files[0] && element.files[0].size > MAX_FILE_SIZE_BYTES; if (isTooBig) { - submits.forEach(submitter => submitter.disabled = true); - warns.forEach( - sib => addRemoveClass(sib, 'is-hidden', false) - ); + submits.forEach((submitter) => (submitter.disabled = true)); + warns.forEach((sib) => addRemoveClass(sib, "is-hidden", false)); } else { - submits.forEach(submitter => submitter.disabled = false); - warns.forEach( - sib => addRemoveClass(sib, 'is-hidden', true) - ); + submits.forEach((submitter) => (submitter.disabled = false)); + warns.forEach((sib) => addRemoveClass(sib, "is-hidden", true)); } } @@ -422,31 +403,27 @@ let BookWyrm = new class { * @return {undefined} */ displayPopUp(url, windowName) { - window.open( - url, - windowName, - "left=100,top=100,width=430,height=600" - ); + window.open(url, windowName, "left=100,top=100,width=430,height=600"); } - duplicateInput (event ) { + duplicateInput(event) { const trigger = event.currentTarget; - const input_id = trigger.dataset['duplicate'] + const input_id = trigger.dataset["duplicate"]; const orig = document.getElementById(input_id); const parent = orig.parentNode; - const new_count = parent.querySelectorAll("input").length + 1 + const new_count = parent.querySelectorAll("input").length + 1; let input = orig.cloneNode(); - input.id += ("-" + (new_count)) - input.value = "" + input.id += "-" + new_count; + input.value = ""; let label = parent.querySelector("label").cloneNode(); - label.setAttribute("for", input.id) + label.setAttribute("for", input.id); - parent.appendChild(label) - parent.appendChild(input) + parent.appendChild(label); + parent.appendChild(input); } /** @@ -461,7 +438,7 @@ let BookWyrm = new class { copyText(textareaEl) { const text = textareaEl.textContent; - const copyButtonEl = document.createElement('button'); + const copyButtonEl = document.createElement("button"); copyButtonEl.textContent = textareaEl.dataset.copytextLabel; copyButtonEl.classList.add( @@ -472,14 +449,14 @@ let BookWyrm = new class { "is-primary", "is-light" ); - copyButtonEl.addEventListener('click', () => { - navigator.clipboard.writeText(text).then(function() { - textareaEl.classList.add('is-success'); - copyButtonEl.classList.replace('is-primary', 'is-success'); + copyButtonEl.addEventListener("click", () => { + navigator.clipboard.writeText(text).then(function () { + textareaEl.classList.add("is-success"); + copyButtonEl.classList.replace("is-primary", "is-success"); copyButtonEl.textContent = textareaEl.dataset.copytextSuccess; }); }); - textareaEl.parentNode.appendChild(copyButtonEl) + textareaEl.parentNode.appendChild(copyButtonEl); } -}(); +})(); diff --git a/bookwyrm/static/js/check_all.js b/bookwyrm/static/js/check_all.js index fd29f2cd..c1ec903f 100644 --- a/bookwyrm/static/js/check_all.js +++ b/bookwyrm/static/js/check_all.js @@ -1,6 +1,5 @@ - -(function() { - 'use strict'; +(function () { + "use strict"; /** * Toggle all descendant checkboxes of a target. @@ -23,12 +22,10 @@ document .querySelectorAll(`#${mainCheckbox.dataset.target} [type="checkbox"]`) - .forEach(checkbox => checkbox.checked = mainCheckbox.checked); + .forEach((checkbox) => (checkbox.checked = mainCheckbox.checked)); } - document - .querySelectorAll('[data-action="toggle-all"]') - .forEach(input => { - input.addEventListener('change', toggleAllCheckboxes); - }); + document.querySelectorAll('[data-action="toggle-all"]').forEach((input) => { + input.addEventListener("change", toggleAllCheckboxes); + }); })(); diff --git a/bookwyrm/static/js/localstorage.js b/bookwyrm/static/js/localstorage.js index b485ed7e..7d0dc9d8 100644 --- a/bookwyrm/static/js/localstorage.js +++ b/bookwyrm/static/js/localstorage.js @@ -1,13 +1,13 @@ /* exported LocalStorageTools */ /* globals BookWyrm */ -let LocalStorageTools = new class { +let LocalStorageTools = new (class { constructor() { - document.querySelectorAll('[data-hide]') - .forEach(t => this.setDisplay(t)); + document.querySelectorAll("[data-hide]").forEach((t) => this.setDisplay(t)); - document.querySelectorAll('.set-display') - .forEach(t => t.addEventListener('click', this.updateDisplay.bind(this))); + document + .querySelectorAll(".set-display") + .forEach((t) => t.addEventListener("click", this.updateDisplay.bind(this))); } /** @@ -23,8 +23,9 @@ let LocalStorageTools = new class { window.localStorage.setItem(key, value); - document.querySelectorAll('[data-hide="' + key + '"]') - .forEach(node => this.setDisplay(node)); + document + .querySelectorAll('[data-hide="' + key + '"]') + .forEach((node) => this.setDisplay(node)); } /** @@ -38,6 +39,6 @@ let LocalStorageTools = new class { let key = node.dataset.hide; let value = window.localStorage.getItem(key); - BookWyrm.addRemoveClass(node, 'is-hidden', value); + BookWyrm.addRemoveClass(node, "is-hidden", value); } -}(); +})(); diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index dbc238c4..b19489c1 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -1,22 +1,21 @@ /* exported StatusCache */ /* globals BookWyrm */ -let StatusCache = new class { +let StatusCache = new (class { constructor() { - document.querySelectorAll('[data-cache-draft]') - .forEach(t => t.addEventListener('change', this.updateDraft.bind(this))); + document + .querySelectorAll("[data-cache-draft]") + .forEach((t) => t.addEventListener("change", this.updateDraft.bind(this))); - document.querySelectorAll('[data-cache-draft]') - .forEach(t => this.populateDraft(t)); + document.querySelectorAll("[data-cache-draft]").forEach((t) => this.populateDraft(t)); - document.querySelectorAll('.submit-status') - .forEach(button => button.addEventListener( - 'submit', - this.submitStatus.bind(this)) - ); + document + .querySelectorAll(".submit-status") + .forEach((button) => button.addEventListener("submit", this.submitStatus.bind(this))); - document.querySelectorAll('.form-rate-stars label.icon') - .forEach(button => button.addEventListener('click', this.toggleStar.bind(this))); + document + .querySelectorAll(".form-rate-stars label.icon") + .forEach((button) => button.addEventListener("click", this.toggleStar.bind(this))); } /** @@ -80,25 +79,26 @@ let StatusCache = new class { event.preventDefault(); - BookWyrm.addRemoveClass(form, 'is-processing', true); - trigger.setAttribute('disabled', null); + BookWyrm.addRemoveClass(form, "is-processing", true); + trigger.setAttribute("disabled", null); - BookWyrm.ajaxPost(form).finally(() => { - // Change icon to remove ongoing activity on the current UI. - // Enable back the element used to submit the form. - BookWyrm.addRemoveClass(form, 'is-processing', false); - trigger.removeAttribute('disabled'); - }) - .then(response => { - if (!response.ok) { - throw new Error(); - } - this.submitStatusSuccess(form); - }) - .catch(error => { - console.warn(error); - this.announceMessage('status-error-message'); - }); + BookWyrm.ajaxPost(form) + .finally(() => { + // Change icon to remove ongoing activity on the current UI. + // Enable back the element used to submit the form. + BookWyrm.addRemoveClass(form, "is-processing", false); + trigger.removeAttribute("disabled"); + }) + .then((response) => { + if (!response.ok) { + throw new Error(); + } + this.submitStatusSuccess(form); + }) + .catch((error) => { + console.warn(error); + this.announceMessage("status-error-message"); + }); } /** @@ -112,12 +112,16 @@ let StatusCache = new class { let copy = element.cloneNode(true); copy.id = null; - element.insertAdjacentElement('beforebegin', copy); + element.insertAdjacentElement("beforebegin", copy); - BookWyrm.addRemoveClass(copy, 'is-hidden', false); - setTimeout(function() { - copy.remove(); - }, 10000, copy); + BookWyrm.addRemoveClass(copy, "is-hidden", false); + setTimeout( + function () { + copy.remove(); + }, + 10000, + copy + ); } /** @@ -131,8 +135,9 @@ let StatusCache = new class { form.reset(); // Clear localstorage - form.querySelectorAll('[data-cache-draft]') - .forEach(node => window.localStorage.removeItem(node.dataset.cacheDraft)); + form.querySelectorAll("[data-cache-draft]").forEach((node) => + window.localStorage.removeItem(node.dataset.cacheDraft) + ); // Close modals let modal = form.closest(".modal.is-active"); @@ -142,8 +147,11 @@ let StatusCache = new class { // Update shelve buttons if (form.reading_status) { - document.querySelectorAll("[data-shelve-button-book='" + form.book.value +"']") - .forEach(button => this.cycleShelveButtons(button, form.reading_status.value)); + document + .querySelectorAll("[data-shelve-button-book='" + form.book.value + "']") + .forEach((button) => + this.cycleShelveButtons(button, form.reading_status.value) + ); } return; @@ -156,7 +164,7 @@ let StatusCache = new class { document.querySelector("[data-controls=" + reply.id + "]").click(); } - this.announceMessage('status-success-message'); + this.announceMessage("status-success-message"); } /** @@ -172,8 +180,9 @@ let StatusCache = new class { let next_identifier = shelf.dataset.shelfNext; // Set all buttons to hidden - button.querySelectorAll("[data-shelf-identifier]") - .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", true)); + button + .querySelectorAll("[data-shelf-identifier]") + .forEach((item) => BookWyrm.addRemoveClass(item, "is-hidden", true)); // Button that should be visible now let next = button.querySelector("[data-shelf-identifier=" + next_identifier + "]"); @@ -183,15 +192,17 @@ let StatusCache = new class { // ------ update the dropdown buttons // Remove existing hidden class - button.querySelectorAll("[data-shelf-dropdown-identifier]") - .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", false)); + button + .querySelectorAll("[data-shelf-dropdown-identifier]") + .forEach((item) => BookWyrm.addRemoveClass(item, "is-hidden", false)); // Remove existing disabled states - button.querySelectorAll("[data-shelf-dropdown-identifier] button") - .forEach(item => item.disabled = false); + button + .querySelectorAll("[data-shelf-dropdown-identifier] button") + .forEach((item) => (item.disabled = false)); - next_identifier = next_identifier == 'complete' ? 'read' : next_identifier; + next_identifier = next_identifier == "complete" ? "read" : next_identifier; // Disable the current state button.querySelector( @@ -206,8 +217,9 @@ let StatusCache = new class { BookWyrm.addRemoveClass(main_button, "is-hidden", true); // Just hide the other two menu options, idk what to do with them - button.querySelectorAll("[data-extra-options]") - .forEach(item => BookWyrm.addRemoveClass(item, "is-hidden", true)); + button + .querySelectorAll("[data-extra-options]") + .forEach((item) => BookWyrm.addRemoveClass(item, "is-hidden", true)); // Close menu let menu = button.querySelector("details[open]"); @@ -235,5 +247,4 @@ let StatusCache = new class { halfStar.checked = "checked"; } } -}(); - +})(); From 2544ea12c77c6f46621dfa45c51a808ca382f46d Mon Sep 17 00:00:00 2001 From: Joachim Date: Fri, 17 Dec 2021 17:00:10 +0100 Subject: [PATCH 038/256] Revert changes on layout --- bookwyrm/static/js/bookwyrm.js | 3 ++ bookwyrm/templates/layout.html | 71 ++++++++++------------------------ 2 files changed, 23 insertions(+), 51 deletions(-) diff --git a/bookwyrm/static/js/bookwyrm.js b/bookwyrm/static/js/bookwyrm.js index ba6cce04..e7586072 100644 --- a/bookwyrm/static/js/bookwyrm.js +++ b/bookwyrm/static/js/bookwyrm.js @@ -427,6 +427,9 @@ let BookWyrm = new class { * with the `data-modal-open` attribute * pointing to a modal by its id. * @return {undefined} + * + * See https://github.com/bookwyrm-social/bookwyrm/pull/1633 + * for information about using the modal. */ handleModalButton(event) { const modalButton = event.currentTarget; diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 4447754b..25aaf1b6 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -158,14 +158,28 @@ {% endwith %} - {% endif %} - - {% if not request.user.is_authenticated %} + {% else %} @@ -244,51 +258,6 @@ -{# Login modal #} -{% if not request.user.is_authenticated %} - -{% endif %} - From f300104c4d71b79d606a886dc6926a1f42de21b0 Mon Sep 17 00:00:00 2001 From: Joachim Date: Fri, 17 Dec 2021 17:29:46 +0100 Subject: [PATCH 039/256] Add reset button style --- bookwyrm/static/css/bookwyrm.css | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/bookwyrm/static/css/bookwyrm.css b/bookwyrm/static/css/bookwyrm.css index 5772c4b8..5b171dab 100644 --- a/bookwyrm/static/css/bookwyrm.css +++ b/bookwyrm/static/css/bookwyrm.css @@ -8,6 +8,36 @@ body { flex-direction: column; } +button { + border: none; + margin: 0; + padding: 0; + width: auto; + overflow: visible; + + background: transparent; + + /* inherit font & color from ancestor */ + color: inherit; + font: inherit; + + /* Normalize `line-height`. Cannot be changed from `normal` in Firefox 4+. */ + line-height: normal; + + /* Corrects font smoothing for webkit */ + -webkit-font-smoothing: inherit; + -moz-osx-font-smoothing: inherit; + + /* Corrects inability to style clickable `input` types in iOS */ + -webkit-appearance: none; +} + +button::-moz-focus-inner { + /* Remove excess padding and border in Firefox 4+ */ + border: 0; + padding: 0; +} + /* Better accessibility for keyboard users */ *:focus-visible { outline-style: auto !important; From ce0e2eb61a5d8201679bdb0a498af0294b666493 Mon Sep 17 00:00:00 2001 From: Joachim Date: Fri, 17 Dec 2021 17:30:14 +0100 Subject: [PATCH 040/256] Handle navbar alignment thank to Bulma helper classes --- bookwyrm/templates/layout.html | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/bookwyrm/templates/layout.html b/bookwyrm/templates/layout.html index 25aaf1b6..2380c4d3 100644 --- a/bookwyrm/templates/layout.html +++ b/bookwyrm/templates/layout.html @@ -36,7 +36,7 @@ -