From 8869f518b8b5274363e1f0ffaa63520ffeebce07 Mon Sep 17 00:00:00 2001 From: Arkadii Yakovets Date: Tue, 10 Sep 2024 12:47:53 -0700 Subject: [PATCH] Add projects page --- backend/Dockerfile.staging | 1 + backend/apps/github/index/__init__.py | 3 + .../apps/github/{index.py => index/issue.py} | 11 ++- backend/apps/github/models/mixins/__init__.py | 5 ++ .../models/{mixins.py => mixins/issue.py} | 71 +------------------ .../apps/github/models/mixins/organization.py | 17 +++++ .../apps/github/models/mixins/repository.py | 55 ++++++++++++++ backend/apps/owasp/api/__init__.py | 1 - backend/apps/owasp/api/search/__init__.py | 4 ++ .../owasp/api/{search.py => search/issue.py} | 15 ++-- backend/apps/owasp/api/search/project.py | 23 ++++++ backend/apps/owasp/index/__init__.py | 3 + .../apps/owasp/{index.py => index/project.py} | 39 +++++++--- backend/apps/owasp/models/mixins/__init__.py | 3 + .../models/{mixins.py => mixins/project.py} | 14 +++- .../search/{issues.html => issue.html} | 8 +-- .../apps/owasp/templates/search/project.html | 58 +++++++++++++++ backend/poetry.lock | 22 +++--- backend/settings/urls.py | 17 +++-- backend/static/js/marked.min.js | 6 -- 20 files changed, 252 insertions(+), 124 deletions(-) create mode 100644 backend/apps/github/index/__init__.py rename backend/apps/github/{index.py => index/issue.py} (93%) create mode 100644 backend/apps/github/models/mixins/__init__.py rename backend/apps/github/models/{mixins.py => mixins/issue.py} (67%) create mode 100644 backend/apps/github/models/mixins/organization.py create mode 100644 backend/apps/github/models/mixins/repository.py create mode 100644 backend/apps/owasp/api/search/__init__.py rename backend/apps/owasp/api/{search.py => search/issue.py} (57%) create mode 100644 backend/apps/owasp/api/search/project.py create mode 100644 backend/apps/owasp/index/__init__.py rename backend/apps/owasp/{index.py => index/project.py} (54%) create mode 100644 backend/apps/owasp/models/mixins/__init__.py rename backend/apps/owasp/models/{mixins.py => mixins/project.py} (85%) rename backend/apps/owasp/templates/search/{issues.html => issue.html} (90%) create mode 100644 backend/apps/owasp/templates/search/project.html delete mode 100644 backend/static/js/marked.min.js diff --git a/backend/Dockerfile.staging b/backend/Dockerfile.staging index 296f0fabf..0e489dc60 100644 --- a/backend/Dockerfile.staging +++ b/backend/Dockerfile.staging @@ -15,6 +15,7 @@ WORKDIR /home/owasp COPY apps apps COPY settings settings +COPY static static COPY templates templates COPY manage.py poetry.lock pyproject.toml wsgi.py ./ diff --git a/backend/apps/github/index/__init__.py b/backend/apps/github/index/__init__.py new file mode 100644 index 000000000..f9d982561 --- /dev/null +++ b/backend/apps/github/index/__init__.py @@ -0,0 +1,3 @@ +"""GitHub app models index.""" + +from apps.github.index.issue import IssueIndex diff --git a/backend/apps/github/index.py b/backend/apps/github/index/issue.py similarity index 93% rename from backend/apps/github/index.py rename to backend/apps/github/index/issue.py index 2c1a38954..422e43017 100644 --- a/backend/apps/github/index.py +++ b/backend/apps/github/index/issue.py @@ -1,4 +1,4 @@ -"""GitHub app index.""" +"""GitHub issue index.""" from datetime import timedelta as td @@ -40,7 +40,7 @@ class IssueIndex(AlgoliaIndex): ) settings = { - "minProximity": 3, + "minProximity": 4, "indexLanguages": ["en"], "customRanking": [ "desc(idx_created_at)", @@ -52,7 +52,6 @@ class IssueIndex(AlgoliaIndex): ], "ranking": [ "typo", - "geo", "words", "filters", "proximity", @@ -61,8 +60,8 @@ class IssueIndex(AlgoliaIndex): "custom", ], "searchableAttributes": [ - "unordered(idx_labels, idx_repository_languages)", "unordered(idx_title, idx_project_name, idx_repository_name)", + "unordered(idx_labels, idx_repository_languages)", "unordered(idx_project_description, idx_repository_description)", "unordered(idx_project_tags, idx_repository_topics)", "unordered(idx_author_login, idx_author_name)", @@ -74,7 +73,6 @@ class IssueIndex(AlgoliaIndex): def get_queryset(self): """Get queryset.""" - # We index all unassigned issues and issues with no activity within 60 days. return ( Issue.objects.select_related( "repository", @@ -84,8 +82,9 @@ def get_queryset(self): "labels", "repository__project_set", ) + # We index all unassigned issues and assigned issues with no activity within 90 days. .filter( Q(assignees__isnull=True) - | Q(assignees__isnull=False, updated_at__lte=timezone.now() - td(days=60)) + | Q(assignees__isnull=False, updated_at__lte=timezone.now() - td(days=90)) ) ) diff --git a/backend/apps/github/models/mixins/__init__.py b/backend/apps/github/models/mixins/__init__.py new file mode 100644 index 000000000..40829ae39 --- /dev/null +++ b/backend/apps/github/models/mixins/__init__.py @@ -0,0 +1,5 @@ +"""GitHub app models mixins.""" + +from apps.github.models.mixins.issue import IssueIndexMixin +from apps.github.models.mixins.organization import OrganizationIndexMixin +from apps.github.models.mixins.repository import RepositoryIndexMixin diff --git a/backend/apps/github/models/mixins.py b/backend/apps/github/models/mixins/issue.py similarity index 67% rename from backend/apps/github/models/mixins.py rename to backend/apps/github/models/mixins/issue.py index 154179c37..dd4f693f7 100644 --- a/backend/apps/github/models/mixins.py +++ b/backend/apps/github/models/mixins/issue.py @@ -1,6 +1,5 @@ -"""GitHub app models mixins.""" +"""GitHub issue mixins.""" -from apps.common.utils import join_values from apps.github.constants import GITHUB_GHOST_USER_LOGIN @@ -121,71 +120,3 @@ def idx_updated_at(self): def idx_url(self): """Return URL for indexing.""" return self.url or None - - -class OrganizationIndexMixin: - """Organization index mixin.""" - - @property - def idx_name(self): - """Return name for indexing.""" - return join_values((self.name, self.login)) - - @property - def idx_company(self): - """Return company for indexing.""" - return join_values((self.company, self.location)) - - -class RepositoryIndexMixin: - """Repository index mixin.""" - - @property - def idx_contributors_count(self): - """Return contributors count for indexing.""" - return self.contributors_count - - @property - def idx_description(self): - """Return description for indexing.""" - return self.description - - @property - def idx_forks_count(self): - """Return forks count for indexing.""" - return self.forks_count - - @property - def idx_languages(self): - """Return languages for indexing.""" - return self.top_languages - - @property - def idx_name(self): - """Return name for indexing.""" - return self.name - - @property - def idx_open_issues_count(self): - """Return open issues count for indexing.""" - return self.open_issues_count - - @property - def idx_pushed_at(self): - """Return pushed at for indexing.""" - return self.pushed_at - - @property - def idx_stars_count(self): - """Return stars count for indexing.""" - return self.stars_count - - @property - def idx_subscribers_count(self): - """Return subscribers count for indexing.""" - return self.stars_count - - @property - def idx_topics(self): - """Return topics for indexing.""" - return self.topics diff --git a/backend/apps/github/models/mixins/organization.py b/backend/apps/github/models/mixins/organization.py new file mode 100644 index 000000000..9dc4468e9 --- /dev/null +++ b/backend/apps/github/models/mixins/organization.py @@ -0,0 +1,17 @@ +"""GitHub organization mixins.""" + +from apps.common.utils import join_values + + +class OrganizationIndexMixin: + """Organization index mixin.""" + + @property + def idx_name(self): + """Return name for indexing.""" + return join_values((self.name, self.login)) + + @property + def idx_company(self): + """Return company for indexing.""" + return join_values((self.company, self.location)) diff --git a/backend/apps/github/models/mixins/repository.py b/backend/apps/github/models/mixins/repository.py new file mode 100644 index 000000000..273594418 --- /dev/null +++ b/backend/apps/github/models/mixins/repository.py @@ -0,0 +1,55 @@ +"""GitHub repository mixins.""" + + +class RepositoryIndexMixin: + """Repository index mixin.""" + + @property + def idx_contributors_count(self): + """Return contributors count for indexing.""" + return self.contributors_count + + @property + def idx_description(self): + """Return description for indexing.""" + return self.description + + @property + def idx_forks_count(self): + """Return forks count for indexing.""" + return self.forks_count + + @property + def idx_languages(self): + """Return languages for indexing.""" + return self.top_languages + + @property + def idx_name(self): + """Return name for indexing.""" + return self.name + + @property + def idx_open_issues_count(self): + """Return open issues count for indexing.""" + return self.open_issues_count + + @property + def idx_pushed_at(self): + """Return pushed at for indexing.""" + return self.pushed_at + + @property + def idx_stars_count(self): + """Return stars count for indexing.""" + return self.stars_count + + @property + def idx_subscribers_count(self): + """Return subscribers count for indexing.""" + return self.stars_count + + @property + def idx_topics(self): + """Return topics for indexing.""" + return self.topics diff --git a/backend/apps/owasp/api/__init__.py b/backend/apps/owasp/api/__init__.py index fbbcd7d04..cb9683024 100644 --- a/backend/apps/owasp/api/__init__.py +++ b/backend/apps/owasp/api/__init__.py @@ -4,4 +4,3 @@ from apps.owasp.api.committee import CommitteeViewSet from apps.owasp.api.event import EventViewSet from apps.owasp.api.project import ProjectViewSet -from apps.owasp.api.search import search_project diff --git a/backend/apps/owasp/api/search/__init__.py b/backend/apps/owasp/api/search/__init__.py new file mode 100644 index 000000000..3ac965a6c --- /dev/null +++ b/backend/apps/owasp/api/search/__init__.py @@ -0,0 +1,4 @@ +"""OWASP app search API.""" + +from apps.owasp.api.search.issue import project_issues +from apps.owasp.api.search.project import projects diff --git a/backend/apps/owasp/api/search.py b/backend/apps/owasp/api/search/issue.py similarity index 57% rename from backend/apps/owasp/api/search.py rename to backend/apps/owasp/api/search/issue.py index 3752b0c77..61dbd539c 100644 --- a/backend/apps/owasp/api/search.py +++ b/backend/apps/owasp/api/search/issue.py @@ -1,4 +1,4 @@ -"""OWASP app search views.""" +"""OWASP app issue search API.""" from algoliasearch_django import raw_search from django.http import JsonResponse @@ -6,8 +6,8 @@ from apps.github.models import Issue -def search_project(request): - """Search project view.""" +def project_issues(request): + """Search project issues view.""" issues_params = { "attributesToRetrieve": [ "idx_created_at", @@ -16,9 +16,10 @@ def search_project(request): "idx_title", "idx_url", ], - "hitsPerPage": 100, + "hitsPerPage": 25, } - issues = raw_search(Issue, request.GET.get("q", ""), issues_params)["hits"] - - return JsonResponse(issues, safe=False) + return JsonResponse( + raw_search(Issue, request.GET.get("q", ""), issues_params)["hits"], + safe=False, + ) diff --git a/backend/apps/owasp/api/search/project.py b/backend/apps/owasp/api/search/project.py new file mode 100644 index 000000000..c638c741f --- /dev/null +++ b/backend/apps/owasp/api/search/project.py @@ -0,0 +1,23 @@ +"""OWASP app project search API.""" + +from algoliasearch_django import raw_search +from django.http import JsonResponse + +from apps.owasp.models import Project + + +def projects(request): + """Search projects view.""" + params = { + "attributesToRetrieve": [ + "idx_name", + "idx_topics", + "idx_url", + ], + "hitsPerPage": 25, + } + + return JsonResponse( + raw_search(Project, request.GET.get("q", ""), params)["hits"], + safe=False, + ) diff --git a/backend/apps/owasp/index/__init__.py b/backend/apps/owasp/index/__init__.py new file mode 100644 index 000000000..eb691cc76 --- /dev/null +++ b/backend/apps/owasp/index/__init__.py @@ -0,0 +1,3 @@ +"""OWASP app models index.""" + +from apps.owasp.index.project import ProjectIndex diff --git a/backend/apps/owasp/index.py b/backend/apps/owasp/index/project.py similarity index 54% rename from backend/apps/owasp/index.py rename to backend/apps/owasp/index/project.py index 3aa6e49bd..4dcae1012 100644 --- a/backend/apps/owasp/index.py +++ b/backend/apps/owasp/index/project.py @@ -1,4 +1,4 @@ -"""OWASP app index.""" +"""OWASP app project index.""" from algoliasearch_django import AlgoliaIndex from algoliasearch_django.decorators import register @@ -13,6 +13,7 @@ class ProjectIndex(AlgoliaIndex): index_name = "projects" fields = ( + "idx_companies", "idx_contributors_count", "idx_description", "idx_forks_count", @@ -21,30 +22,46 @@ class ProjectIndex(AlgoliaIndex): "idx_level", "idx_name", "idx_organizations", - "idx_companies", "idx_stars_count", "idx_tags", "idx_topics", + "idx_type", "idx_updated_at", + "idx_url", ) settings = { + "minProximity": 4, + "indexLanguages": ["en"], "customRanking": [ "desc(idx_level)", "desc(idx_stars_count)", - "desc(idx_forks_count)", "desc(idx_contributors_count)", + "desc(idx_forks_count)", + "desc(idx_updated_at)", + ], + "ranking": [ + "typo", + "words", + "filters", + "proximity", + "attribute", + "exact", + "custom", ], "searchableAttributes": [ - "idx_description", - "idx_languages", - "idx_leaders", - "idx_name", - "idx_organizations", - "idx_companies", - "idx_tags", - "idx_topics", + "unordered(idx_name)", + "unordered(idx_tags, idx_topics, idx_languages)", + "unordered(idx_description)", + "unordered(idx_companies, idx_leaders, idx_organizations)", ], } should_index = "is_indexable" + + def get_queryset(self): + """Get queryset.""" + return Project.objects.prefetch_related( + "organizations", + "repositories", + ) diff --git a/backend/apps/owasp/models/mixins/__init__.py b/backend/apps/owasp/models/mixins/__init__.py new file mode 100644 index 000000000..0d5e31c24 --- /dev/null +++ b/backend/apps/owasp/models/mixins/__init__.py @@ -0,0 +1,3 @@ +"""OWASP app models mixins.""" + +from apps.owasp.models.mixins.project import ProjectIndexMixin diff --git a/backend/apps/owasp/models/mixins.py b/backend/apps/owasp/models/mixins/project.py similarity index 85% rename from backend/apps/owasp/models/mixins.py rename to backend/apps/owasp/models/mixins/project.py index c40a07d55..8a34bd810 100644 --- a/backend/apps/owasp/models/mixins.py +++ b/backend/apps/owasp/models/mixins/project.py @@ -1,4 +1,4 @@ -"""OWASP app models mixins.""" +"""OWASP app project mixins.""" from apps.common.utils import join_values @@ -18,7 +18,7 @@ def idx_contributors_count(self): @property def idx_description(self): - """Return description count for indexing.""" + """Return description for indexing.""" return self.description @property @@ -66,7 +66,17 @@ def idx_topics(self): """Return topics for indexing.""" return self.topics + @property + def idx_type(self): + """Return type for indexing.""" + return self.type + @property def idx_updated_at(self): """Return updated at for indexing.""" return self.updated_at + + @property + def idx_url(self): + """Return URL for indexing.""" + return self.owasp_url diff --git a/backend/apps/owasp/templates/search/issues.html b/backend/apps/owasp/templates/search/issue.html similarity index 90% rename from backend/apps/owasp/templates/search/issues.html rename to backend/apps/owasp/templates/search/issue.html index 2f1c0d5ff..2aadba9d6 100644 --- a/backend/apps/owasp/templates/search/issues.html +++ b/backend/apps/owasp/templates/search/issue.html @@ -6,10 +6,9 @@ -

- Find a Project + Find an issue to work on

name="q" placeholder="Type To Search..." type="search" - hx-get="{% url 'api-projects-contribute' %}" + hx-get="{% url 'search-project-issues' %}" hx-indicator=".htmx-indicator" hx-swap="none" hx-target="#search-results" - hx-trigger="input changed delay:1000ms, search" + hx-trigger="load input changed delay:1000ms, search" /> Searching... @@ -35,7 +34,6 @@

const resultsContainer = document.getElementById('search-results'); resultsContainer.innerHTML = ''; - const md = window.markdownit(); hits.forEach((hit) => { const highlightedTitle = hit._highlightResult.idx_title.value; diff --git a/backend/apps/owasp/templates/search/project.html b/backend/apps/owasp/templates/search/project.html new file mode 100644 index 000000000..a886a1ef6 --- /dev/null +++ b/backend/apps/owasp/templates/search/project.html @@ -0,0 +1,58 @@ +{% load static %} + + + + + + + + +

Find a project

+ + Searching... + + + +
diff --git a/backend/poetry.lock b/backend/poetry.lock index 36175e9fa..356f27f5e 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -45,17 +45,17 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] [[package]] name = "boto3" -version = "1.35.15" +version = "1.35.16" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.35.15-py3-none-any.whl", hash = "sha256:c8e3567a843bee89b826b71916748088386ccd48014f0f55f56288215a686048"}, - {file = "boto3-1.35.15.tar.gz", hash = "sha256:5e286daa84f945e4c57b133fc96bd2abbcf4066e5d4e63c591ce5e949913d6fd"}, + {file = "boto3-1.35.16-py3-none-any.whl", hash = "sha256:9c5b0ce4a25bb78d659478d1c552f1dbb7ff275aab3263bb41cdbef8bca28693"}, + {file = "boto3-1.35.16.tar.gz", hash = "sha256:9b96c210678cf430b16b49dee87db30f46044602bb9a605a465e1900f468a43f"}, ] [package.dependencies] -botocore = ">=1.35.15,<1.36.0" +botocore = ">=1.35.16,<1.36.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -64,13 +64,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.35.15" +version = "1.35.16" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.15-py3-none-any.whl", hash = "sha256:a01a7668941c9276ca7697fb0b09a47ab1f13e585c5ca6551270528f4e086de8"}, - {file = "botocore-1.35.15.tar.gz", hash = "sha256:bbfe4f6cd417d1d097900db062f1017e5185775acdeccd0eff1ec0f499633242"}, + {file = "botocore-1.35.16-py3-none-any.whl", hash = "sha256:3564a980d95ff2861a6ca74313173d8778aa659125c63cf49c93ad23896c63b1"}, + {file = "botocore-1.35.16.tar.gz", hash = "sha256:1b48c94e8a4bbe23143f3d1c21a32b9ffc7476b651ef42371ab45d678f6dbfbc"}, ] [package.dependencies] @@ -79,7 +79,7 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} [package.extras] -crt = ["awscrt (==0.21.2)"] +crt = ["awscrt (==0.21.5)"] [[package]] name = "certifi" @@ -998,13 +998,13 @@ tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"] [[package]] name = "pytest" -version = "8.3.2" +version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"}, - {file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [package.dependencies] diff --git a/backend/settings/urls.py b/backend/settings/urls.py index 5cfff85c1..8bf16c5a3 100644 --- a/backend/settings/urls.py +++ b/backend/settings/urls.py @@ -12,7 +12,8 @@ from rest_framework import routers from apps.github.api.urls import router as github_router -from apps.owasp.api import search_project +from apps.owasp.api.search import project_issues as search_project_issues +from apps.owasp.api.search import projects as search_projects from apps.owasp.api.urls import router as owasp_router from apps.owasp.views import home_page @@ -22,11 +23,17 @@ urlpatterns = [ path("api/v1/", include(router.urls)), - path("api/v1/search/", search_project, name="api-projects-contribute"), + path("api/v1/owasp/search/issue", search_project_issues, name="search-project-issues"), + path("api/v1/owasp/search/project", search_projects, name="search-projects"), path( - "projects/contribute", - TemplateView.as_view(template_name="search/issues.html"), - name="projects-contribute", + "projects/", + TemplateView.as_view(template_name="search/project.html"), + name="projects", + ), + path( + "projects/contribute/", + TemplateView.as_view(template_name="search/issue.html"), + name="project-issues", ), path("", home_page), path("a/", admin.site.urls), diff --git a/backend/static/js/marked.min.js b/backend/static/js/marked.min.js deleted file mode 100644 index f724cc44e..000000000 --- a/backend/static/js/marked.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * marked v14.1.2 - a markdown parser - * Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed) - * https://github.com/markedjs/marked - */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s=/[&<>"']/,r=new RegExp(s.source,"g"),i=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,l=new RegExp(i.source,"g"),o={"&":"&","<":"<",">":">",'"':""","'":"'"},a=e=>o[e];function c(e,t){if(t){if(s.test(e))return e.replace(r,a)}else if(i.test(e))return e.replace(l,a);return e}const h=/(^|[^\[])\^/g;function p(e,t){let n="string"==typeof e?e:e.source;t=t||"";const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(h,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}function u(e){try{e=encodeURI(e).replace(/%25/g,"%")}catch{return null}return e}const k={exec:()=>null};function g(e,t){const n=e.replace(/\|/g,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(/ \|/);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^(?: {1,4}| {0,3}\t)/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:f(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t){const n=e.match(/^(\s+)(?:```)/);if(null===n)return t;const s=n[1];return t.split("\n").map((e=>{const t=e.match(/^\s+/);if(null===t)return e;const[n]=t;return n.length>=s.length?e.slice(s.length):e})).join("\n")}(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=f(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:f(t[0],"\n")}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let e=f(t[0],"\n").split("\n"),n="",s="";const r=[];for(;e.length>0;){let t=!1;const i=[];let l;for(l=0;l/.test(e[l]))i.push(e[l]),t=!0;else{if(t)break;i.push(e[l])}e=e.slice(l);const o=i.join("\n"),a=o.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,"\n $1").replace(/^ {0,3}>[ \t]?/gm,"");n=n?`${n}\n${o}`:o,s=s?`${s}\n${a}`:a;const c=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(a,r,!0),this.lexer.state.top=c,0===e.length)break;const h=r[r.length-1];if("code"===h?.type)break;if("blockquote"===h?.type){const t=h,i=t.raw+"\n"+e.join("\n"),l=this.blockquote(i);r[r.length-1]=l,n=n.substring(0,n.length-t.raw.length)+l.raw,s=s.substring(0,s.length-t.text.length)+l.text;break}if("list"!==h?.type);else{const t=h,i=t.raw+"\n"+e.join("\n"),l=this.list(i);r[r.length-1]=l,n=n.substring(0,n.length-h.raw.length)+l.raw,s=s.substring(0,s.length-t.raw.length)+l.raw,e=i.substring(r[r.length-1].raw.length).split("\n")}}return{type:"blockquote",raw:n,tokens:r,text:s}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim();const s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=new RegExp(`^( {0,3}${n})((?:[\t ][^\\n]*)?(?:\\n|$))`);let l=!1;for(;e;){let n=!1,s="",o="";if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;s=t[0],e=e.substring(s.length);let a=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=!a.trim(),p=0;if(this.options.pedantic?(p=2,o=a.trimStart()):h?p=t[1].length+1:(p=t[2].search(/[^ ]/),p=p>4?1:p,o=a.slice(p),p+=t[1].length),h&&/^[ \t]*$/.test(c)&&(s+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=new RegExp(`^ {0,${Math.min(3,p-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),n=new RegExp(`^ {0,${Math.min(3,p-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),r=new RegExp(`^ {0,${Math.min(3,p-1)}}(?:\`\`\`|~~~)`),i=new RegExp(`^ {0,${Math.min(3,p-1)}}#`),l=new RegExp(`^ {0,${Math.min(3,p-1)}}<[a-z].*>`,"i");for(;e;){const u=e.split("\n",1)[0];let k;if(c=u,this.options.pedantic?(c=c.replace(/^ {1,4}(?=( {4})*[^ ])/g," "),k=c):k=c.replace(/\t/g," "),r.test(c))break;if(i.test(c))break;if(l.test(c))break;if(t.test(c))break;if(n.test(c))break;if(k.search(/[^ ]/)>=p||!c.trim())o+="\n"+k.slice(p);else{if(h)break;if(a.replace(/\t/g," ").search(/[^ ]/)>=4)break;if(r.test(a))break;if(i.test(a))break;if(n.test(a))break;o+="\n"+c}h||c.trim()||(h=!0),s+=u+"\n",e=e.substring(u.length+1),a=k.slice(p)}}r.loose||(l?r.loose=!0:/\n[ \t]*\n[ \t]*$/.test(s)&&(l=!0));let u,k=null;this.options.gfm&&(k=/^\[[ xX]\] /.exec(o),k&&(u="[ ] "!==k[0],o=o.replace(/^\[[ xX]\] +/,""))),r.items.push({type:"list_item",raw:s,task:!!k,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=s}r.items[r.items.length-1].raw=r.items[r.items.length-1].raw.trimEnd(),r.items[r.items.length-1].text=r.items[r.items.length-1].text.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e"space"===e.type)),n=t.length>0&&t.some((e=>/\n.*\n/.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",s=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:n,title:s}}}table(e){const t=this.rules.block.table.exec(e);if(!t)return;if(!/[:|]/.test(t[2]))return;const n=g(t[1]),s=t[2].replace(/^\||\| *$/g,"").split("|"),r=t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[],i={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===s.length){for(const e of s)/^ *-+: *$/.test(e)?i.align.push("right"):/^ *:-+: *$/.test(e)?i.align.push("center"):/^ *:-+ *$/.test(e)?i.align.push("left"):i.align.push(null);for(let e=0;e({text:e,tokens:this.lexer.inline(e),header:!1,align:i.align[t]}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:c(t[1])}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&/^/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&/^$/.test(e))return;const t=f(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;let n=0;for(let s=0;s-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),/^$/.test(e)?n.slice(1):n.slice(1,-1)),d(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(/\s+/g," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return d(n,e,n[0],this.lexer)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(/[\p{L}\p{N}]/u))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(/\n/g," ");const n=/[^ ]/.test(e),s=/^ /.test(e)&&/ $/.test(e);return n&&s&&(e=e.substring(1,e.length-1)),e=c(e,!0),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=c(t[1]),n="mailto:"+e):(e=c(t[1]),n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=c(t[0]),n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=c(t[0]),n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){let e;return e=this.lexer.state.inRawBlock?t[0]:c(t[0]),{type:"text",raw:t[0],text:e}}}}const b=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,w=/(?:[*+-]|\d{1,9}[.)])/,m=p(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,w).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).getRegex(),y=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,$=/(?!\s*\])(?:\\.|[^\[\]\\])+/,z=p(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",$).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),T=p(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,w).getRegex(),R="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",_=/|$))/,A=p("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ \t]*)+\\n|$))","i").replace("comment",_).replace("tag",R).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),S=p(y).replace("hr",b).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",R).getRegex(),I={blockquote:p(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",S).getRegex(),code:/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,def:z,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:b,html:A,lheading:m,list:T,newline:/^(?:[ \t]*(?:\n|$))+/,paragraph:S,table:k,text:/^[^\n]+/},E=p("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",b).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3}\t)[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",R).getRegex(),q={...I,table:E,paragraph:p(y).replace("hr",b).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",E).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|textarea|!--)").replace("tag",R).getRegex()},Z={...I,html:p("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",_).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:k,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:p(y).replace("hr",b).replace("heading"," *#{1,6} *[^\n]").replace("lheading",m).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},P=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,L=/^( {2,}|\\)\n(?!\s*$)/,v="\\p{P}\\p{S}",Q=p(/^((?![*_])[\spunctuation])/,"u").replace(/punctuation/g,v).getRegex(),B=p(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,v).getRegex(),M=p("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,v).getRegex(),O=p("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,v).getRegex(),j=p(/\\([punct])/,"gu").replace(/punct/g,v).getRegex(),D=p(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),C=p(_).replace("(?:--\x3e|$)","--\x3e").getRegex(),H=p("^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",C).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),U=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,X=p(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",U).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),F=p(/^!?\[(label)\]\[(ref)\]/).replace("label",U).replace("ref",$).getRegex(),N=p(/^!?\[(ref)\](?:\[\])?/).replace("ref",$).getRegex(),G={_backpedal:k,anyPunctuation:j,autolink:D,blockSkip:/\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g,br:L,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:k,emStrongLDelim:B,emStrongRDelimAst:M,emStrongRDelimUnd:O,escape:P,link:X,nolink:N,punctuation:Q,reflink:F,reflinkSearch:p("reflink|nolink(?!\\()","g").replace("reflink",F).replace("nolink",N).getRegex(),tag:H,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\!!(s=n.call({lexer:this},e,t))&&(e=e.substring(s.raw.length),t.push(s),!0)))))if(s=this.tokenizer.space(e))e=e.substring(s.raw.length),1===s.raw.length&&t.length>0?t[t.length-1].raw+="\n":t.push(s);else if(s=this.tokenizer.code(e))e=e.substring(s.raw.length),r=t[t.length-1],!r||"paragraph"!==r.type&&"text"!==r.type?t.push(s):(r.raw+="\n"+s.raw,r.text+="\n"+s.text,this.inlineQueue[this.inlineQueue.length-1].src=r.text);else if(s=this.tokenizer.fences(e))e=e.substring(s.raw.length),t.push(s);else if(s=this.tokenizer.heading(e))e=e.substring(s.raw.length),t.push(s);else if(s=this.tokenizer.hr(e))e=e.substring(s.raw.length),t.push(s);else if(s=this.tokenizer.blockquote(e))e=e.substring(s.raw.length),t.push(s);else if(s=this.tokenizer.list(e))e=e.substring(s.raw.length),t.push(s);else if(s=this.tokenizer.html(e))e=e.substring(s.raw.length),t.push(s);else if(s=this.tokenizer.def(e))e=e.substring(s.raw.length),r=t[t.length-1],!r||"paragraph"!==r.type&&"text"!==r.type?this.tokens.links[s.tag]||(this.tokens.links[s.tag]={href:s.href,title:s.title}):(r.raw+="\n"+s.raw,r.text+="\n"+s.raw,this.inlineQueue[this.inlineQueue.length-1].src=r.text);else if(s=this.tokenizer.table(e))e=e.substring(s.raw.length),t.push(s);else if(s=this.tokenizer.lheading(e))e=e.substring(s.raw.length),t.push(s);else{if(i=e,this.options.extensions&&this.options.extensions.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(i=e.substring(0,t+1))}if(this.state.top&&(s=this.tokenizer.paragraph(i)))r=t[t.length-1],n&&"paragraph"===r?.type?(r.raw+="\n"+s.raw,r.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=r.text):t.push(s),n=i.length!==e.length,e=e.substring(s.raw.length);else if(s=this.tokenizer.text(e))e=e.substring(s.raw.length),r=t[t.length-1],r&&"text"===r.type?(r.raw+="\n"+s.raw,r.text+="\n"+s.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=r.text):t.push(s);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n,s,r,i,l,o,a=e;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(i=this.tokenizer.rules.inline.reflinkSearch.exec(a));)e.includes(i[0].slice(i[0].lastIndexOf("[")+1,-1))&&(a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(i=this.tokenizer.rules.inline.blockSkip.exec(a));)a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(i=this.tokenizer.rules.inline.anyPunctuation.exec(a));)a=a.slice(0,i.index)+"++"+a.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;e;)if(l||(o=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.escape(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.tag(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.link(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.emStrong(e,a,o))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.codespan(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.br(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.del(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.autolink(e))e=e.substring(n.raw.length),t.push(n);else if(this.state.inLink||!(n=this.tokenizer.url(e))){if(r=e,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(n=this.tokenizer.inlineText(r))e=e.substring(n.raw.length),"_"!==n.raw.slice(-1)&&(o=n.raw.slice(-1)),l=!0,s=t[t.length-1],s&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}else e=e.substring(n.raw.length),t.push(n);return t}}class te{options;parser;constructor(t){this.options=t||e.defaults}space(e){return""}code({text:e,lang:t,escaped:n}){const s=(t||"").match(/^\S*/)?.[0],r=e.replace(/\n$/,"")+"\n";return s?'
'+(n?r:c(r,!0))+"
\n":"
"+(n?r:c(r,!0))+"
\n"}blockquote({tokens:e}){return`
\n${this.parser.parse(e)}
\n`}html({text:e}){return e}heading({tokens:e,depth:t}){return`${this.parser.parseInline(e)}\n`}hr(e){return"
\n"}list(e){const t=e.ordered,n=e.start;let s="";for(let t=0;t\n"+s+"\n"}listitem(e){let t="";if(e.task){const n=this.checkbox({checked:!!e.checked});e.loose?e.tokens.length>0&&"paragraph"===e.tokens[0].type?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&"text"===e.tokens[0].tokens[0].type&&(e.tokens[0].tokens[0].text=n+" "+e.tokens[0].tokens[0].text)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" "}):t+=n+" "}return t+=this.parser.parse(e.tokens,!!e.loose),`
  • ${t}
  • \n`}checkbox({checked:e}){return"'}paragraph({tokens:e}){return`

    ${this.parser.parseInline(e)}

    \n`}table(e){let t="",n="";for(let t=0;t${s}`),"\n\n"+t+"\n"+s+"
    \n"}tablerow({text:e}){return`\n${e}\n`}tablecell(e){const t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`\n`}strong({tokens:e}){return`${this.parser.parseInline(e)}`}em({tokens:e}){return`${this.parser.parseInline(e)}`}codespan({text:e}){return`${e}`}br(e){return"
    "}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:n}){const s=this.parser.parseInline(n),r=u(e);if(null===r)return s;let i='
    ",i}image({href:e,title:t,text:n}){const s=u(e);if(null===s)return n;let r=`${n}{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new te(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if(["options","parser"].includes(n))continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new x(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new re;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if(["options","block"].includes(n))continue;const s=n,r=e.hooks[s],i=t[s];re.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return ee.lex(e,t??this.defaults)}parser(e,t){return se.parse(e,t??this.defaults)}parseMarkdown(e){return(t,n)=>{const s={...n},r={...this.defaults,...s},i=this.onError(!!r.silent,!!r.async);if(!0===this.defaults.async&&!1===s.async)return i(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(null==t)return i(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof t)return i(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(t)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);const l=r.hooks?r.hooks.provideLexer():e?ee.lex:ee.lexInline,o=r.hooks?r.hooks.provideParser():e?se.parse:se.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(t):t).then((e=>l(e,r))).then((e=>r.hooks?r.hooks.processAllTokens(e):e)).then((e=>r.walkTokens?Promise.all(this.walkTokens(e,r.walkTokens)).then((()=>e)):e)).then((e=>o(e,r))).then((e=>r.hooks?r.hooks.postprocess(e):e)).catch(i);try{r.hooks&&(t=r.hooks.preprocess(t));let e=l(t,r);r.hooks&&(e=r.hooks.processAllTokens(e)),r.walkTokens&&this.walkTokens(e,r.walkTokens);let n=o(e,r);return r.hooks&&(n=r.hooks.postprocess(n)),n}catch(e){return i(e)}}}onError(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="

    An error occurred:

    "+c(n.message+"",!0)+"
    ";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const le=new ie;function oe(e,t){return le.parse(e,t)}oe.options=oe.setOptions=function(e){return le.setOptions(e),oe.defaults=le.defaults,n(oe.defaults),oe},oe.getDefaults=t,oe.defaults=e.defaults,oe.use=function(...e){return le.use(...e),oe.defaults=le.defaults,n(oe.defaults),oe},oe.walkTokens=function(e,t){return le.walkTokens(e,t)},oe.parseInline=le.parseInline,oe.Parser=se,oe.parser=se.parse,oe.Renderer=te,oe.TextRenderer=ne,oe.Lexer=ee,oe.lexer=ee.lex,oe.Tokenizer=x,oe.Hooks=re,oe.parse=oe;const ae=oe.options,ce=oe.setOptions,he=oe.use,pe=oe.walkTokens,ue=oe.parseInline,ke=oe,ge=se.parse,fe=ee.lex;e.Hooks=re,e.Lexer=ee,e.Marked=ie,e.Parser=se,e.Renderer=te,e.TextRenderer=ne,e.Tokenizer=x,e.getDefaults=t,e.lexer=fe,e.marked=oe,e.options=ae,e.parse=ke,e.parseInline=ue,e.parser=ge,e.setOptions=ce,e.use=he,e.walkTokens=pe}));